BZOJ 1176 Mokia(CDQ分治)
2018-03-30 17:09
344 查看
题目链接:BZOJ 1176
题目大意:维护一个W*W的矩阵,初始值均为S。每次操作可以增加某格子的权值或询问某子矩阵的总权值(修改操作数M<=160000,询问数Q<=10000,W<=2000000)。
题解:CDQ分治。查询操作可以分成4个(1,1)到(x,y)的子矩形的权值和查询,再加加减减。先把操作按x坐标为第一关键字,y为第二关键字排序,然后按操作的先后分治。分治的每一层里,计算左边的修改对右边的查询造成的影响,由于保证了右边询问的x坐标不小于左边修改的x坐标,用一个下标为y坐标的树状数组统计就好了,然后分治下去。
总结:感觉做CDQ分治的题要考虑好左边对右边的影响怎么统计、每一层需不需要清空、需不需要保证有序。
题目大意:维护一个W*W的矩阵,初始值均为S。每次操作可以增加某格子的权值或询问某子矩阵的总权值(修改操作数M<=160000,询问数Q<=10000,W<=2000000)。
题解:CDQ分治。查询操作可以分成4个(1,1)到(x,y)的子矩形的权值和查询,再加加减减。先把操作按x坐标为第一关键字,y为第二关键字排序,然后按操作的先后分治。分治的每一层里,计算左边的修改对右边的查询造成的影响,由于保证了右边询问的x坐标不小于左边修改的x坐标,用一个下标为y坐标的树状数组统计就好了,然后分治下去。
code(没有权限,并不保证AC TAT)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define maxn 2000005 #define maxm 640005 #define maxq 10005 #define lowbit(x) ((x)&(-x)) inline int read() { char c=getchar(); int num=0,f=1; while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); } while (c<='9'&&c>='0') { num=num*10+c-'0'; c=getchar(); } return num*f; } int n,bit[maxn],ans[maxq]; struct data{ int opt,id,qid,x,y,c; data(int _opt=0,int _id=0,int _qid=0,int _x=0,int _y=0,int _c=0) { opt=_opt; id=_id; qid=_qid; x=_x; y=_y; c=_c; } }c[maxm],tmp[maxm]; inline void add(int pos,int val) { for (;pos<=n;pos+=lowbit(pos)) bit[pos]+=val; } inline int sum(int pos) { int ret=0; for (;pos;pos-=lowbit(pos)) ret+=bit[pos]; return ret; } inline int cmp(data a,data b) { return (a.x!=b.x)?(a.x<b.x):((a.y!=b.y)?(a.y<b.y):(a.opt<b.opt)); } void cdq(int l,int r) { if (l==r) return; int mid=l+r>>1; for (int i=l;i<=r;i++) { if (c[i].opt==1&&c[i].id<=mid) add(c[i].y,c[i].c); else if (c[i].opt==2&&c[i].id>mid) ans[c[i].qid]+=c[i].c*sum(c[i].y); } for (int i=l;i<=r;i++) //清空树状数组,即保证了每次只统计当前区间前一半修改对后一半询问的影响 if (c[i].opt==1&&c[i].id<=mid) add(c[i].y,-c[i].c); int h1=l,h2=mid; for (int i=l;i<=r;i++) // 保证分治到每一层时所有操作是x坐标有序的 if (c[i].id<=mid) tmp[h1++]=c[i]; else tmp[++h2]=c[i]; for (int i=l;i<=r;i++) c[i]=tmp[i]; cdq(l,mid); cdq(mid+1,r); } int main() { int s=read(),n=read(),tot=0,id=0; while (true) { int opt=read(); if (opt==3) break; if (opt==1) { int x=read(),y=read(),w=read(); tot++; data oh(1,tot,0,x,y,w); c[tot]=oh; } else { int x1=read(),y1=read(),x2=read(),y2=read(); id++; tot++; data d1(2,tot,id,x2,y2,1); c[tot]=d1; tot++; data d2(2,tot,id,x1-1,y2,-1); c[tot]=d2; tot++; data d3(2,tot,id,x2,y1-1,-1); c[tot]=d3; tot++; data d4(2,tot,id,x1-1,y1-1,1); c[tot]=d4; ans[id]=(y2-y1+1)*(x2-x1+1)*s; } } sort(c+1,c+tot+1,cmp); cdq(1,tot); for (int i=1;i<=id;i++) printf("%d\n",ans[i]); return 0; }
总结:感觉做CDQ分治的题要考虑好左边对右边的影响怎么统计、每一层需不需要清空、需不需要保证有序。
相关文章推荐
- bzoj 1176: [Balkan2007]Mokia 【CDQ分治】
- [学习笔记]CDQ分治 bzoj1176 [Baltic2007] Mokia
- bzoj 1176 [Balkan2007]Mokia 【CDQ分治】
- [BZOJ1176][[Balkan2007]Mokia][CDQ分治]
- bzoj 1176: [Balkan2007]Mokia&&2683: 简单题 -- cdq分治
- BZOJ1176 [Balkan2007]Mokia 【CDQ分治】
- BZOJ 1176: [Balkan2007]Mokia [CDQ分治]
- [BZOJ1176]-Mokia-CDQ分治
- cdq分治入门--BZOJ1176: [Balkan2007]Mokia
- bzoj 1176: [Balkan2007]Mokia(cdq分治)
- BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )
- BZOJ 1176([Balkan2007]Mokia-CDQ分治-分治询问)
- BZOJ1176 [Balkan2007]Mokia 【CDQ分治】
- 【bzoj 1176】Mokia(CDQ分治)
- BZOJ 1176([Balkan2007]Mokia-CDQ分治-分治询问)
- 【BZOJ】1176: [Balkan2007]Mokia(cdq分治)
- BZOJ 1176: [Balkan2007]Mokia (CDQ分治)
- 【BZOJ1176】Mokia(CDQ分治)
- bzoj 1176 [Balkan2007]Mokia - CDQ分治 - 树状数组
- bzoj 1176: Mokia CDQ分治