ACdream--1157(CDQ分治)
2015-08-09 18:48:32
【传送门】CDQ第二道启蒙题~
题意:有最多10^5种操作,每种操作可以是(1)添加一条线段【L,R】,(2)删除第 i 条添加的线段,(3)查询有多少现存的线段完全包含【l,r】这条线段
思路:考虑CDQ分治,有BZOJ 1176的经验,可以先将所有操作按照左端点进行排序,然后将操作按照时间一分为二,先处理前半边修改对后半边询问造成的影响,由于已经按照左端点排过序了,我们可以用树状数组维护每个修改的右端点,加线段就给右端点处+1,删除就给右端点处-1,查询的话只要查右端点 r 的右边的右端点数就可以了(此时左端点一定被包含),由于端点值很大,需要提前离散化。
处理这些影响后还原前半边操作的影响。
然后按照时间把前半边操作放在左边,后半边操作放在右边,分别处理左 / 右半边操作。
#include <cstdio> #include <ctime> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB push_back typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 200010; int N,pos[MAXN],sz; int c[MAXN],ans[MAXN]; int b[MAXN]; int lowbit(int x){ return x & (-x); } void Update(int x,int d){ while(x < MAXN){ c[x] += d; x += lowbit(x); } } int Getsum(int x){ int res = 0; while(x){ res += c[x]; x -= lowbit(x); } return res; } struct Node{ int l,r,f,id; bool operator < (const Node &b) const{ if(l == b.l) return f > b.f; return l < b.l; } }P[MAXN],tmp[MAXN]; void CDQ(int l,int r){ if(l == r) return; //l --> mid , mid + 1 --> r int mid = getmid(l,r); for(int i = l; i <= r; ++i){ if(P[i].id <= mid && P[i].f == 0) Update(P[i].r,1); else if(P[i].id <= mid && P[i].f > 0) Update(P[i].r,-1); else if(P[i].id > mid && P[i].f == -1) ans[P[i].id] += Getsum(sz) - Getsum(P[i].r - 1); } for(int i = l; i <= r; ++i){ if(P[i].id <= mid && P[i].f == 0) Update(P[i].r,-1); else if(P[i].id <= mid && P[i].f > 0) Update(P[i].r,1); } int c1 = l,c2 = mid + 1; for(int i = l; i <= r; ++i){ if(P[i].id <= mid) tmp[c1++] = P[i]; else tmp[c2++] = P[i]; } for(int i = l; i <= r; ++i) P[i] = tmp[i]; CDQ(l,mid); CDQ(mid + 1,r); } int main(){ char s[10]; while(scanf("%d",&N) != EOF){ int cnt = 0; sz = 0; memset(ans,0,sizeof(ans)); memset(c,0,sizeof(c)); for(int i = 1; i <= N; ++i){ scanf("%s%d",s,&P[i].l); if(s[0] == 'C'){ //删 P[i].f = P[i].l; //删第几条边 P[i].l = P[pos[P[i].f]].l; P[i].r = P[pos[P[i].f]].r; } else{ scanf("%d",&P[i].r); if(s[0] == 'D'){ pos[++cnt] = i; P[i].f = 0; //加 } else{ P[i].f = -1; //查 } } P[i].id = i; b[++sz] = P[i].l; b[++sz] = P[i].r; } sort(b + 1,b + sz + 1); sz = unique(b + 1,b + sz + 1) - b - 1; for(int i = 1; i <= N; ++i){ P[i].l = lower_bound(b + 1,b + sz + 1,P[i].l) - b; P[i].r = lower_bound(b + 1,b + sz + 1,P[i].r) - b; } sort(P + 1,P + N + 1); CDQ(1,N); for(int i = 1; i <= N; ++i) if(P[i].f == -1) printf("%d\n",ans[i]); } return 0; }