您的位置:首页 > 其它

西南科技大学第九届程序设计竞赛B题解题报告(线段树版)

2013-05-22 00:14 204 查看
题目链接http://acm.swust.edu.cn/oj/contest/58/908/

题目大意:给你N个物品,每个物品有两个属性V1,V2,把它插入到k+1的位置(类似数组的插入),求它前一个物品的V1,不存在输出-1,和后一个物品的V2,不存在输出-1。

解题思路,可以维护一颗线段树,求得最后物品的序列,题目中样例最终的序列就是4,1,5,2,3,。表示第1个物品最终在4这个位置,第2个物品最终在1这个位置……

怎么使用线段树求得这个序列呢?

这个题有一个重要的性质,就是你把这个序列倒着看,最后一个插入的物品的位置一定是最终位置,不会改变!

因此我们维护一颗线段树,线段树节点记录区间还有多少的空位,我们倒着插入这个序列,最终得到的序列一定是正确的!

拿样例来举例,第5个物品先插入第3个位置(我定义的位置是1到n,转化一下即可),如图

1 - 5

↙ ↘

1-3 4-5

↙ ↘ ↙ ↘

1-2 3(5) 4 5

↙ ↘

1 2

然后是4插入第2个位置

1 - 5

↙ ↘

1-3 4-5

↙ ↘ ↙ ↘

1-2 3(5) 4 5

↙ ↘

1 2(4)

然后是3插入第2位置

1 - 5

↙ ↘

1-3 4-5

↙ ↘ ↙ ↘

1-2 3(5) 4(3) 5

↙ ↘

1 2(4)

后面的也一样了

得到这个序列以后,就可以顺着看这个序列了,每次查询它前面和后面有没有物品,然后插入这个物品。

这个时候又维护一颗线段树,节点记录插入的物品数,由于相对位置已经给出,查询的时候二分即可。

具体实现如下

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define lc l,m,index<<1
#define rc m+1,r,index<<1|1
#define N 20005
int cnt[N<<2];//节点信息
int ord
;//相对序列
int aim
;//绝对序列
int ex
;//绝对位置是哪个物品
int v1
,v2
;//物品属性
int n;
void build(int l,int r,int index)//建第一颗树
{
int m=(l+r)>>1;
cnt[index]=r-l+1;
if(l==r)return;
build(lc);
build(rc);
}
int query(int id,int l,int r,int index)//第一颗树的查询和维护
{
int m=(l+r)>>1;
cnt[index]--;
if(l==r)return l;
if(id>=cnt[index<<1])return query(id-cnt[index<<1],rc);
else return query(id,lc);
}
int query2(int id,int l,int r,int index)//第二棵树的查询
{
if(id==-1||!cnt[index])return -1;
if(l==r)return l;
int m=(l+r)>>1;
if(id>=cnt[index<<1])return query2(id-cnt[index<<1],rc);
else return query2(id,lc);
}
void updata(int id,int l,int r,int index)//第二棵树的维护
{
int m=(l+r)>>1;
cnt[index]++;
if(l==r)return;
if(id<=m)updata(id,lc);
else updata(id,rc);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
int i,pos;
build(1,n,1);//第一颗树
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&v1[i],&v2[i],&ord[i]);
ord[i]++;
}
for(i=n;i>=1;i--)
{
aim[i]=query(ord[i],1,n,1);//计算最终位置
ex[aim[i]]=i;
}
memset(cnt,0,sizeof cnt);//第二棵树
for(i=1;i<=n;i++)
{
pos=query2(ord[i]-1,1,n,1);//查找前面
if(pos==-1)printf("-1 ");
else printf("%d ",v1[ex[pos]]);
pos=query2(ord[i],1,n,1);//查找后面
if(pos==-1)printf("-1\n");
else printf("%d\n",v2[ex[pos]]);
updata(aim[i],1,n,1);//插入物品
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐