ACdream 1157 Segments CDQ分治
Posted Lsxxxxxxxxxxxxx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACdream 1157 Segments CDQ分治相关的知识,希望对你有一定的参考价值。
题目链接:https://vjudge.net/problem/ACdream-1157
题意:
Problem Description
由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)
给出N,接下来N行,每行是3种类型之一
Input
多组数据,每组数据N
接下来N行,每行是三种操作之一(1 <= N <= 10^5)
Output
Sample Input
6 D 1 100 D 3 8 D 4 10 Q 3 8 C 1 Q 3 8
Sample Output
2 1
Hint
注意,删除第i条增加的线段,不是说第i行,而是说第i次增加。
比如
D 1 10
Q 1 10
D 2 3
D 3 4
Q 5 6
D 5 6
C 2是删除D 2 3
C 4是删除D 5 6
解法:CDQ分治,将删除操作看作插入一条数量为-1的线段,查询操作看作插入一条数量为0的线段,用cnt[i]表示第i次插入的线段被之前插入的线段包含的次数,按操作顺序进行分治,每次统计[l,mid+1]中有多少元素j满足j.y>=i.y,j.x<=i.x,其中mid+1<=i<=r,这个过程可以通过对两个区间都以x为第一关键字降序排,以y为第二关键字升序排,对于[mid+1,r]中的每个i(i为数量为0的元素,即为查询),将[l,mid]中所有满足j.y>=i.y的j以j.x为下标,cnt[j]为键值插入到树状数组中,那么每次只需统计树状数组中下标小于等于i.x的元素键值之和累加到cnt[i]中即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5+10; int n, h[maxn], tot; struct node{ int x,y,cnt,id,ans; bool operator<(const node &rhs) const{ if(y!=rhs.y)return y>rhs.y; return x<rhs.x; } }p[maxn],q[maxn]; bool cmp(node a, node b){ return a.id<b.id; } struct BIT{ int b[maxn]; void init(){ memset(b, 0, sizeof(b)); } inline int lowbit(int x){ return (x&(-x)); } void add(int x, int v){ while(x<=tot){ b[x]+=v; x+=lowbit(x); } } int query(int x){ int ret = 0; while(x){ ret += b[x]; x -= lowbit(x); } return ret; } }bit; void CDQ(int l, int r){ if(l == r) return; int mid = (l+r)/2; CDQ(l,mid); CDQ(mid+1,r); sort(p+l,p+mid+1); sort(p+mid+1,p+r+1); int j=l; for(int i=mid+1; i<=r; i++){ for(;j<=mid&&p[j].y>=p[i].y;j++) bit.add(p[j].x, p[j].cnt); if(!p[i].cnt) p[i].ans+=bit.query(p[i].x); } for(int i=l; i<j; i++) bit.add(p[i].x, -p[i].cnt); merge(p+l,p+mid+1,p+mid+1,p+r+1,q); for(int i=0; i<r-l+1; i++) p[l+i]=q[i]; } int res, l[maxn], r[maxn]; int main() { while(~scanf("%d", &n)) { bit.init(); tot=0,res=1; for(int i=1; i<=n; i++){ p[i].id = i, p[i].ans = 0; char op[3]; scanf("%s", op); if(op[0] == ‘D‘){ scanf("%d%d",&p[i].x,&p[i].y); p[i].cnt=1; l[res]=p[i].x,r[res++]=p[i].y; h[++tot]=p[i].x,h[++tot]=p[i].y; } else if(op[0]==‘Q‘){ scanf("%d%d",&p[i].x,&p[i].y); p[i].cnt=0; h[++tot]=p[i].x,h[++tot]=p[i].y; } else{ int temp; scanf("%d", &temp); p[i].x=l[temp],p[i].y=r[temp]; p[i].cnt=-1; } } sort(h+1,h+tot+1); tot = unique(h+1,h+tot+1)-h-1; for(int i=1; i<=n; i++){ p[i].x=lower_bound(h+1,h+tot+1,p[i].x)-h; p[i].y=lower_bound(h+1,h+tot+1,p[i].y)-h; } CDQ(1, n); sort(p+1,p+n+1,cmp); for(int i=1; i<=n; i++){ if(!p[i].cnt) printf("%d\n", p[i].ans); } } return 0; }
以上是关于ACdream 1157 Segments CDQ分治的主要内容,如果未能解决你的问题,请参考以下文章