西南科技大学第九届程序设计竞赛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)
后面的也一样了
得到这个序列以后,就可以顺着看这个序列了,每次查询它前面和后面有没有物品,然后插入这个物品。
这个时候又维护一颗线段树,节点记录插入的物品数,由于相对位置已经给出,查询的时候二分即可。
具体实现如下
题目大意:给你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; }
相关文章推荐
- 福州大学第十三届程序设计竞赛_重现解题报告
- 华东交通大学2013ACM“双基”程序设计竞赛 解题报告
- 福州大学第十二届程序设计竞赛 解题报告
- 2017广东工业大学程序设计竞赛决赛【解题报告】【待补全】
- 2015 中国大学生程序设计竞赛解题报告
- 2016 大学生程序设计竞赛亚洲区域赛青岛赛区(ICPC)解题报告
- 华东交通大学2013年ACM“双基”程序设计竞赛 解题报告
- 浙江省第6届大学生程序设计竞赛解题报告
- 2013级新生程序设计基础竞赛-正式赛 F 异或最大值 解题报告
- UESTC 第五届ACM趣味程序设计竞赛第四场(正式赛) 解题报告
- 2017广东工业大学程序设计竞赛决赛【解题报告】[补完√]
- 浙江省第8届程序设计竞赛解题报告
- 2014嘉杰信息杯ACM/ICPC湖南程序设计邀请赛暨第六届湘潭市程序设计竞赛 解题报告
- 2016年湖南省第十二届大学生计算机程序设计竞赛 解题报告
- 华东交通大学2014年ACM“双基”程序设计竞赛部分解题报告
- 团体程序设计天梯赛-练习集 L3-002. 堆栈 线段树 单点更新 解题报告
- UESTC-第五届ACM趣味程序设计竞赛第四场(正式赛)--不完全解题报告
- 山东省第四届ACM大学生程序设计竞赛解题报告(部分)
- UESTC 第五届ACM趣味程序设计竞赛第一场(热身赛,非原创题) 解题报告
- “光庭杯”第五届华中北区程序设计邀请赛 暨 WHU第八届程序设计竞赛(部分解题报告)