lp4390 [BOI2007]Mokia 摩基亚
题目概述:
带修改的二维数点。
题目思路:
把一个询问拆成4个,那么我们很容易想到cdq分治,直接做即可。
用一些小技巧可以优化代码。老久没写cdq了,果然挂了,i=j=1是怎么回事。
题目代码:
#include<cstdio> #include<algorithm> const int MaQ1=10000,MaQ2=160000; #define opt1 (true) #define opt2 (false) struct ques{ int t,x,y,num; bool opt; friend bool operator <(ques a,ques b){ if(a.t!=b.t) return a.t<b.t; return a.x+a.y>b.x+b.y; } }q[MaQ1+MaQ2*4+5],ls[MaQ1+MaQ2*4+5]; int n,m,k; inline int lowbit(int a){return a&-a;} int c[2000005]; void add(int val,int r){ for(;val<=n;val+=lowbit(val)) c[val]+=r; return ; } int que(int val){ int r; for(r=0;val;val-=lowbit(val)) r+=c[val]; return r; } int st[1000005],con; void clear(int val){ for(;val<=n;val+=lowbit(val)) c[val]=0; return ; } void prout(){ /*printf("\n"); for(int i=1;i<=k;i++){ printf("%d:%d %d %d\n",i,q[i].t,q[i].x,q[i].y); } printf("\n");*/ return ; } void cdq(int l,int r){ if(l==r) return ; #define mid (l+r>>1) cdq(l,mid);cdq(mid+1,r); //BUG A //int i=1,j=1,k=mid+1; int i=l,j=l,k=mid+1; while(j<=mid&&k<=r){ if(q[j].x<=q[k].x){ if(q[j].opt){ add(q[j].y,q[j].num); st[con++]=q[j].y; } ls[i++]=q[j++]; } else{ if(!q[k].opt) q[k].num+=que(q[k].y); ls[i++]=q[k++]; } } while(j<=mid){ if(q[j].opt){ add(q[j].y,q[j].num); st[con++]=q[j].y; } ls[i++]=q[j++]; } while(k<=r){ if(!q[k].opt) q[k].num+=que(q[k].y); ls[i++]=q[k++]; } #undef mid for(int i=0;i<con;i++) clear(st[i]); con=0; for(int i=l;i<=r;i++) q[i]=ls[i]; prout(); return ; } int main(){ scanf("%*d%d",&n); int opt; while(true){ scanf("%d",&opt); if(opt==3) break; ++m; if(opt==1){ int x,y,z; scanf("%d%d%d",&x,&y,&z); q[++k]= (ques) {m,x,y,z,1}; } else{ int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); q[++k]=(ques) { m,x1-1,y1-1,0,opt2 }; q[++k]=(ques) { m,x1-1,y2,0,opt2 }; q[++k]=(ques) { m,x2,y1-1,0,opt2 }; q[++k]=(ques) { m,x2,y2,0,opt2 }; } } prout(); cdq(1,k); std::sort(q+1,q+k+1); prout(); int now=1; for(int i=1;i<=m;i++){ if(q[now].opt==opt1){++now;continue;} if(q[now].opt==opt2) printf("%d\n",q[now].num+q[now+3].num-q[now+1].num-q[now+2].num),now+=4; } return 0; }