ACdream1157 Segments(CDQ分治 + 线段树)

题目这么说的:

进行如下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感觉还是不错的。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 
  6 int tree[222222<<2],N,x,y;
  7 void update(int i,int j,int k){
  8     if(i==j){
  9         tree[k]+=y;
 10         return;
 11     }
 12     int mid=i+j>>1;
 13     if(x<=mid) update(i,mid,k<<1);
 14     else update(mid+1,j,k<<1|1);
 15     tree[k]=tree[k<<1]+tree[k<<1|1];
 16 }
 17 int query(int i,int j,int k){
 18     if(x<=i && j<=y){
 19         return tree[k];
 20     }
 21     int mid=i+j>>1,res=0;
 22     if(x<=mid) res+=query(i,mid,k<<1);
 23     if(y>mid) res+=query(mid+1,j,k<<1|1);
 24     return res;
 25 }
 26 
 27 struct Query{
 28     int idx,type,anspos;
 29     int x,y;
 30     bool operator<(const Query &q)const{
 31         return x<q.x;
 32     }
 33 }que[111111],tmp[111111];
 34 
 35 int ans[111111];
 36 
 37 void cdq(int l,int r){
 38     if(l>=r) return;
 39     int mid=l+r>>1,i=l,j=mid+1;
 40     for(int k=l; k<=r; ++k){
 41         if(que[k].idx<=mid) tmp[i++]=que[k];
 42         else tmp[j++]=que[k];
 43     }
 44     for(int k=l; k<=r; ++k) que[k]=tmp[k];
 45 
 46     for(i=mid+1,j=l; i<=r; ++i){
 47         if(que[i].type!=3) continue;
 48         for( ; j<=mid && que[j].x<=que[i].x; ++j){
 49             if(que[j].type==3) continue;
 50             x=que[j].y; y=(que[j].type==1) ? 1 : -1;
 51             update(0,N-1,1);
 52         }
 53         x=que[i].y; y=N-1;
 54         ans[que[i].anspos]+=query(0,N-1,1);
 55     }
 56     for(i=l; i<j; ++i){
 57         if(que[i].type==3) continue;
 58         x=que[i].y; y=(que[i].type==1) ? -1 : 1;
 59         update(0,N-1,1);
 60     }
 61     cdq(l,mid); cdq(mid+1,r);
 62 }
 63 
 64 int segx[111111],segy[111111],sn;
 65 int point[222222],pn;
 66 int main(){
 67     char op;
 68     int n,a,b;
 69     while(~scanf("%d",&n)){
 70         int cnt=0;
 71         memset(ans,0,sizeof(ans));
 72         sn=0; pn=0;
 73         for(int i=0; i<n; ++i){
 74             scanf(" %c",&op);
 75             if(op=='D'){
 76                 scanf("%d%d",&a,&b);
 77                 segx[++sn]=a; segy[sn]=b;
 78                 point[pn++]=a; point[pn++]=b;
 79                 que[i].idx=i; que[i].type=1; que[i].x=a; que[i].y=b;
 80             }else if(op=='C'){
 81                 scanf("%d",&a);
 82                 que[i].idx=i; que[i].type=2; que[i].x=segx[a]; que[i].y=segy[a];
 83             }else{
 84                 scanf("%d%d",&a,&b);
 85                 point[pn++]=a; point[pn++]=b;
 86                 que[i].idx=i; que[i].type=3; que[i].x=a; que[i].y=b; que[i].anspos=++cnt;
 87             }
 88         }
 89 
 90         sort(point,point+pn);
 91         pn=unique(point,point+pn)-point;
 92         for(N=1; N<pn; N<<=1);
 93 
 94         for(int i=0; i<n; ++i){
 95             que[i].x=lower_bound(point,point+pn,que[i].x)-point;
 96             que[i].y=lower_bound(point,point+pn,que[i].y)-point;
 97         }
 98 
 99         sort(que,que+n);
100         cdq(0,n-1);
101 
102         for(int i=1; i<=cnt; ++i){
103             printf("%d\n",ans[i]);
104         }
105     }
106     return 0;
107 }

 

转载于:https://www.cnblogs.com/WABoss/p/5701844.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值