BZOJ 1176: [Balkan2007]Mokia | CDQ分治
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1176
题解:
题目s无用
其实是CDQ还是能够看出来的,就是怎么做需要考虑考虑
首先对于一个区间的询问我们可以通过二维前缀和的方式转化成四个前缀询问,这样就可以用树状数组这类数据结构很快维护一维
然后把操作们按x坐标排序(x是第一维),这样树状数组就只用维护y轴信息即可
因为我们只用考虑一个序列中前半段时间修改对后半段时间答案的影响,所以树状数组维护一下y轴信息即可
#include<cstdio> #include<algorithm> #include<cstring> #define M 2000010 using namespace std; int s,w,op,x1,y1,x2,y2,cnt=1,ans[M],t[M],m; struct Op { int type,t,x,y,k,id; bool operator < (const Op &b)const { if (x==b.x && y==b.y) return type<b.type; if (x==b.x) return y<b.y; return x<b.x; } }p[M],tmp[M]; inline void AddQuery() { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); p[++cnt].id=++m;p[cnt].t=cnt,p[cnt].x=x1-1;p[cnt].y=y1-1;p[cnt].k=1;p[cnt].type=2; p[++cnt].id=m;p[cnt].t=cnt,p[cnt].x=x2;p[cnt].y=y2;p[cnt].k=1;p[cnt].type=2; p[++cnt].id=m;p[cnt].t=cnt,p[cnt].x=x1-1;p[cnt].y=y2;p[cnt].k=-1;p[cnt].type=2; p[++cnt].id=m;p[cnt].t=cnt,p[cnt].x=x2;p[cnt].y=y1-1;p[cnt].k=-1;p[cnt].type=2; } inline void Insert(int x,int k) { for (;x<M;x+=x&-x) t[x]+=k; } inline int Query(int x) { int ret=0; for (;x;x-=x&-x) ret+=t[x]; return ret; } inline void solve(int l,int r) { if (l==r) return ; int mid=l+r>>1,i=l,j=mid+1; for (int k=l;k<=r;k++) if (p[k].t<=mid && p[k].type==1) Insert(p[k].y,p[k].k); else if (p[k].t>mid && p[k].type==2) ans[p[k].id]+=p[k].k*Query(p[k].y); for (int k=l;k<=r;k++) { if (p[k].t<=mid && p[k].type==1) Insert(p[k].y,-p[k].k); if (p[k].t<=mid) tmp[i++]=p[k]; else tmp[j++]=p[k]; } for (i=l;i<=r;i++) p[i]=tmp[i]; solve(l,mid); solve(mid+1,r); } int main() { printf("%d %d\n",p[0].t,p[1].t); scanf("%d%d",&s,&w); while (scanf("%d",&op)!=EOF && op!=3) if (op==1) scanf("%d%d%d",&p[cnt].x,&p[cnt].y,&p[cnt].k),p[cnt].type=1,p[cnt++].t=cnt++; else AddQuery(); sort(p+1,p+1+cnt); solve(1,cnt); for (int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }