ACdream1157 Segments(CDQ分治 + 线段树)
2016-07-24 22:39
302 查看
题目这么说的:
进行如下3种类型操作:
1)D L R(1 <= L <= R <= 1000000000) 增加一条线段[L,R]
2)C i (1-base) 删除第i条增加的线段,保证每条插入线段最多插入一次,且这次删除操作一定合法
3) Q L R(1 <= L <= R <= 1000000000) 查询目前存在的线段中有多少条线段完全包含[L,R]这个线段,线段X被线段Y完全包含即LY <= LX <= RX <= RY)
初学CDQ分治是看了Balkan OI 2007 Mokia那题的解法。两题类似,这题做法也不难想出:
每次对操作的区间进行分治时,统计左半边更新操作对右半边查询操作的影响,影响的前提是更新操作的L小于等于查询操作的L且R要大于等于查询的R,这个通过一开始把L按从小到大排序,分治时便可从大到小遍历,同时用线段树维护R出现次数即可。
其实我一开始看错题,以为询问的是有几条线段包含在给定区间里面,写完后发现才样例过不了。。不过改一下就好了,然后1A感觉还是不错的。
进行如下3种类型操作:
1)D L R(1 <= L <= R <= 1000000000) 增加一条线段[L,R]
2)C i (1-base) 删除第i条增加的线段,保证每条插入线段最多插入一次,且这次删除操作一定合法
3) Q L R(1 <= L <= R <= 1000000000) 查询目前存在的线段中有多少条线段完全包含[L,R]这个线段,线段X被线段Y完全包含即LY <= LX <= RX <= RY)
初学CDQ分治是看了Balkan OI 2007 Mokia那题的解法。两题类似,这题做法也不难想出:
每次对操作的区间进行分治时,统计左半边更新操作对右半边查询操作的影响,影响的前提是更新操作的L小于等于查询操作的L且R要大于等于查询的R,这个通过一开始把L按从小到大排序,分治时便可从大到小遍历,同时用线段树维护R出现次数即可。
其实我一开始看错题,以为询问的是有几条线段包含在给定区间里面,写完后发现才样例过不了。。不过改一下就好了,然后1A感觉还是不错的。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int tree[222222<<2],N,x,y; void update(int i,int j,int k){ if(i==j){ tree[k]+=y; return; } int mid=i+j>>1; if(x<=mid) update(i,mid,k<<1); else update(mid+1,j,k<<1|1); tree[k]=tree[k<<1]+tree[k<<1|1]; } int query(int i,int j,int k){ if(x<=i && j<=y){ return tree[k]; } int mid=i+j>>1,res=0; if(x<=mid) res+=query(i,mid,k<<1); if(y>mid) res+=query(mid+1,j,k<<1|1); return res; } struct Query{ int idx,type,anspos; int x,y; bool operator<(const Query &q)const{ return x<q.x; } }que[111111],tmp[111111]; int ans[111111]; void cdq(int l,int r){ if(l>=r) return; int mid=l+r>>1,i=l,j=mid+1; for(int k=l; k<=r; ++k){ if(que[k].idx<=mid) tmp[i++]=que[k]; else tmp[j++]=que[k]; } for(int k=l; k<=r; ++k) que[k]=tmp[k]; for(i=mid+1,j=l; i<=r; ++i){ if(que[i].type!=3) continue; for( ; j<=mid && que[j].x<=que[i].x; ++j){ if(que[j].type==3) continue; x=que[j].y; y=(que[j].type==1) ? 1 : -1; update(0,N-1,1); } x=que[i].y; y=N-1; ans[que[i].anspos]+=query(0,N-1,1); } for(i=l; i<j; ++i){ if(que[i].type==3) continue; x=que[i].y; y=(que[i].type==1) ? -1 : 1; update(0,N-1,1); } cdq(l,mid); cdq(mid+1,r); } int segx[111111],segy[111111],sn; int point[222222],pn; int main(){ char op; int n,a,b; while(~scanf("%d",&n)){ int cnt=0; memset(ans,0,sizeof(ans)); sn=0; pn=0; for(int i=0; i<n; ++i){ scanf(" %c",&op); if(op=='D'){ scanf("%d%d",&a,&b); segx[++sn]=a; segy[sn]=b; point[pn++]=a; point[pn++]=b; que[i].idx=i; que[i].type=1; que[i].x=a; que[i].y=b; }else if(op=='C'){ scanf("%d",&a); que[i].idx=i; que[i].type=2; que[i].x=segx[a]; que[i].y=segy[a]; }else{ scanf("%d%d",&a,&b); point[pn++]=a; point[pn++]=b; que[i].idx=i; que[i].type=3; que[i].x=a; que[i].y=b; que[i].anspos=++cnt; } } sort(point,point+pn); pn=unique(point,point+pn)-point; for(N=1; N<pn; N<<=1); for(int i=0; i<n; ++i){ que[i].x=lower_bound(point,point+pn,que[i].x)-point; que[i].y=lower_bound(point,point+pn,que[i].y)-point; } sort(que,que+n); cdq(0,n-1); for(int i=1; i<=cnt; ++i){ printf("%d\n",ans[i]); } } return 0; }
相关文章推荐
- 10.程序包
- LeetCode--77_Combinations
- Issure: LookupError: unknown encoding: cp65001
- 如何把项目放到GitHub上
- Spring Data JPA 学习笔记(一)
- Linux驱动开发必看
- Leetcode 18. 4Sum (Medium) (cpp)
- 【iOS开发】简易加法计算器的实现
- Codeforces Round #364 (Div. 1) B. Connecting Universities
- Oracle 学习:约束、查询语句
- 【HDU杭电 2035】人见人爱A^B
- 使用jdk1.7与spring 2.5 jar包冲突的解决
- 开发工具集
- 设计模式之工厂模式——应用最广泛的模式
- Android的线程与线程池
- UVA 11624 Fire! 【特殊BFS】
- 【Java】排序之Java的Sort函数
- POJ 3468 A Simple Problem with Integers
- DFS及其应用 专题
- 9.函数