陈丹琪分治
cdq提出的一种分治手段。
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88335#problem/B
题意,+ a b操作是增加一个线段【a,b】,?c d 是询问此前有多少个线段满足a<=c<d<=b
暴力n^2
如果所有的查询都在增加线段之后,我们可以把线段和查询都按照左端点从小到大排序,然后单调队列两个指针。当线段左端点a<=查询c的时候,线段指针后移,并将线段的右端点加入树状数组中,当遇到a>c的时候,说明此后的线段都不满足了,这个查询的答案就是树状数组中y》=d的个数,可以用sum(MAX)-sum(y-1)得出,复杂度logn,然后查询的指针后移一个,这样每个查询和每个线段都只会走一次,总体复杂度nlogn。类似离线的查询。
但是这个题目中插入和查询的穿插出现的,就是在线的查询,通过cdq分治就可以转换为上述离线的查询。
分治思想是解决上述问题定义为solve(l,r),答案就是solve(1,n)
每次将区间等分为l到mid,mid+1到r
左区间的+都可以对右区间的?产生贡献,并且时间上都早于右边的查询,因此可以利用上诉离线算法在nlogn内完成,
然后递归解决左右区间内部的问题。logn。
总体复杂度n*log(n)*log(n)
1 //#define debug 2 //#define txtout 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<cctype> 8 #include<ctime> 9 #include<iostream> 10 #include<algorithm> 11 #include<vector> 12 #include<queue> 13 #include<stack> 14 #include<map> 15 #include<set> 16 #define mt(a,b) memset(a,b,sizeof(a)) 17 using namespace std; 18 typedef long long LL; 19 const double eps=1e-8; 20 const double pi=acos(-1.0); 21 const int inf=0x3f3f3f3f; 22 const int M=5e5+10; 23 struct G { 24 char op[4]; 25 int x,y,id; 26 friend bool operator <(const G &a,const G &b){ 27 return a.x<b.x; 28 } 29 } g[M]; 30 vector<int> a; 31 vector<G> p,q; 32 map<int,int> mp; 33 int res[M]; 34 class One_Tree_Array { //一维树状数组 35 typedef int typev; 36 typev a[M]; 37 public: 38 void init() { 39 mt(a,0); 40 } 41 int lowb(int t) { 42 return t&(-t); 43 } 44 void add(int i,typev v) { 45 for(; i<M; a[i]+=v,i+=lowb(i)); 46 } 47 typev sum(int i) { 48 typev s=0; 49 for(; i>0; s+=a[i],i-=lowb(i)); 50 return s; 51 } 52 }tree; 53 int bigy; 54 void cdq(int L,int R) { 55 if(L==R) return ; 56 int mid=(L+R)>>1; 57 p.clear(); 58 for(int i=L; i<=mid; i++) { 59 if(g[i].op[0]=='?') continue; 60 p.push_back(g[i]); 61 } 62 q.clear(); 63 for(int i=mid+1; i<=R; i++) { 64 if(g[i].op[0]=='+') continue; 65 q.push_back(g[i]); 66 } 67 sort(p.begin(),p.end()); 68 sort(q.begin(),q.end()); 69 int lp=p.size(); 70 int lq=q.size(); 71 int len=0; 72 for(int i=0,j=0;i<lq;i++){ 73 while(j<lp&&p[j].x<=q[i].x){ 74 tree.add(p[j].y,1); 75 j++; 76 len=j; 77 } 78 res[q[i].id]+=tree.sum(bigy)-tree.sum(q[i].y-1); 79 } 80 for(int i=0;i<len;i++){ 81 tree.add(p[i].y,-1); 82 } 83 cdq(L,mid); 84 cdq(mid+1,R); 85 } 86 int main() { 87 #ifdef txtout 88 freopen("in.txt","r",stdin); 89 freopen("out.txt","w",stdout); 90 #endif 91 int n; 92 while(~scanf("%d",&n)) { 93 a.clear(); 94 for(int i=1; i<=n; i++) { 95 scanf("%s%d%d",g[i].op,&g[i].x,&g[i].y); 96 // a.push_back(g[i].x); 97 a.push_back(g[i].y); 98 } 99 sort(a.begin(),a.end()); 100 int la=unique(a.begin(),a.end())-a.begin(); 101 mp.clear(); 102 for(int i=0; i<la; i++) { 103 mp[a[i]]=i+1; 104 } 105 bigy=0; 106 for(int i=1; i<=n; i++) { 107 // g[i].x=mp[g[i].x]; 108 g[i].y=mp[g[i].y]; 109 bigy=max(bigy,g[i].y); 110 g[i].id=i; 111 res[i]=0; 112 } 113 tree.init(); 114 cdq(1,n); 115 for(int i=1; i<=n; i++) { 116 if(g[i].op[0]=='+') continue; 117 printf("%d\n",res[i]); 118 } 119 } 120 return 0; 121 }
end