【BZOJ 1176】 [Balkan2007]Mokia
来源:互联网 发布:python ljust函数 编辑:程序博客网 时间:2024/04/30 20:42
1176: [Balkan2007]Mokia
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 736 Solved: 306
[Submit][Status]
Description
维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.
Input
第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小
接下来每行为一下三种输入之一(不包含引号):
"1 x y a"
"2 x1 y1 x2 y2"
"3"
输入1:你需要把(x,y)(第x行第y列)的格子权值增加a
输入2:你需要求出以左上角为(x1,y1),右下角为(x2,y2)的矩阵内所有格子的权值和,并输出
输入3:表示输入结束
Output
对于每个输入2,输出一行,即输入2的答案
Sample Input
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
5
HINT
保证答案不会超过int范围
CDQ分治模板题。
CDQ分治就是把一些修改,查询离线来做。
而修改的先后顺序对结果没有影响,因此可以通过改变修改的顺序来降低时空复杂度。
若第k个操作是查询操作,我们只要把1-k-1中所有修改操作对k的影响计算出来,就能保证查询的正确性。
所以Solve(l,r)要做的就是让任意选择k(为查询操作),l-k-1的修改操作都被计算过了。
这道题因为空间限制,只能开一维树状数组,所以考虑CDQ分治。
先把子矩阵和转换为二维前缀和pre:
sum[x1,y1,x2,y2]=pre[x2,y2]-pre[x2,y1-1]-pre[x1-1,y2]+pre[x1-1,y1-1]
然后按照x排序,Solve(l,r)的时候计算(l,m)的修改对(m+1,r)上的查询的影响。然后再递归Solve(l,m) Solve(m+1,r)
接下来说明一下正确性:
1.因为是按照x排序的,所以每个询问都只包含x小于他的所有修改,所以可以用一维
2.在递归的过程中,可以不重不漏的计算(1,k-1)中的修改对k的影响:Solve(l,r)先计算计算的是(l,m)的修改对(m+1,r)的影响;
假设k在(l,m)的某一位置,当前操作下没有对他进行修改,但是(l,k-1)的修改会在Solve(l,m)时对他进行计算,不会漏掉;
假设k在(m+1,r)的某一位置,(l,m)对他的影响刚刚算完了(Solve(l,r)),在Solve(m+1,r)的时候会递归计算出(m+1,k-1)对k的影响,因此l-k-1的修改对k的影响就都计算出来了。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#define maxn 2000005using namespace std;struct data{int x,y,pos,c,id,z;}a[maxn],b[maxn];int n,w,k,t,tot;int s[maxn],ans[maxn];bool cmp(data a,data b){return (a.x<b.x||(a.x==b.x&&a.pos<b.pos));}void Fz(int k,int aa,int b,int c){a[k].x=aa,a[k].y=b,a[k].z=c;}int lowbit(int x){return x&(-x);}void Add(int x,int v){for (int i=x;i<=w;i+=lowbit(i))s[i]+=v;}int Getsum(int x){int ans=0;for (int i=x;i;i-=lowbit(i))ans+=s[i];return ans;}void Solve(int l,int r){int m=(l+r)>>1;if (l==r) return;for (int i=l;i<=r;i++) //计算(l,m)的修改操作对(m+1,r)的查询操作的影响{if (a[i].c==1&&a[i].pos<=m) Add(a[i].y,a[i].z);if (a[i].c!=1&&a[i].pos>m) ans[a[i].id]+=a[i].z*Getsum(a[i].y);}for (int i=l;i<=r;i++) //消除当前影响if (a[i].pos<=m&&a[i].c==1) Add(a[i].y,-a[i].z);int t1=l,t2=m+1;for (int i=l;i<=r;i++)if (a[i].pos<=m) b[t1++]=a[i];else b[t2++]=a[i];for (int i=l;i<=r;i++) //为递归计算做准备a[i]=b[i];Solve(l,m);Solve(m+1,r);t1=l,t2=m+1;for (int i=l;i<=r;i++) //还原递归前的数组if ((a[t1].x<a[t2].x||t2>r)&&(t1<=m)) b[i]=a[t1++]; else b[i]=a[t2++];for (int i=l;i<=r;i++)a[i]=b[i];}int main(){ scanf("%d%d",&k,&w);n=0;while (1){n++;scanf("%d",&a[n].c);if (a[n].c==3){n--;break;}if (a[n].c==1){scanf("%d%d%d",&a[n].x,&a[n].y,&a[n].z);}else{int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);ans[++tot]=(x2-x1+1)*(y2-y1+1)*k;Fz(n,x2,y2,1);Fz(++n,x1-1,y2,-1);Fz(++n,x2,y1-1,-1);Fz(++n,x1-1,y1-1,1);for (int i=n;i>=n-3;i--)a[i].id=tot;}}for (int i=1;i<=n;i++)a[i].pos=i;sort(a+1,a+1+n,cmp);Solve(1,n);for (int i=1;i<=tot;i++)printf("%d\n",ans[i]);return 0;}
感悟:
目前对CDQ分治的理解就是:
有M次询问,按照给定顺序来算需要M次,而CDQ分治要算M*logM次,因此本题时间的复杂度为O(logW*MlogM)约为500万。
- 【BZOJ 1176】 [Balkan2007]Mokia
- bzoj 1176: [Balkan2007]Mokia
- BZOJ 1176 [Balkan2007] Mokia
- bzoj 1176: [Balkan2007]Mokia
- bzoj 1176 [Balkan2007]Mokia
- bzoj 1176: [Balkan2007]Mokia
- 【分治】 BZOJ 1176 [Balkan2007]Mokia
- BZOJ 1176: [Balkan2007]Mokia CDQ
- BZOJ 1176 [Balkan2007]Mokia CDQ分治
- BZOJ 1176: [Balkan2007]Mokia CDQ分治
- bzoj 1176: [Balkan2007]Mokia 【CDQ分治】
- bzoj 1176: [Balkan2007]Mokia(cdq分治)
- 【BZOJ 1176】 [Balkan2007]Mokia cdq分治
- BZOJ 1176: [Balkan2007]Mokia (CDQ分治)
- BZOJ 1176: [Balkan2007]Mokia/2683: 简单题
- 1176: [Balkan2007]Mokia
- BZOJ 1176([Balkan2007]Mokia-CDQ分治-分治询问)
- [BZOJ 1176]Balkan2007 Mokia cdq分治一血!
- Oracle数据访问组件ODAC的安装方法
- Java泛型详解
- <mvc:annotation-driven />注解意义
- Git详解之三 Git分支
- c++ 将文件内容写入到数组
- 【BZOJ 1176】 [Balkan2007]Mokia
- Android studio导入模块 提示已经存在的问题
- python中的自省
- 感觉很重要
- IOS 查看lib库(.a)支持的处理器架构、合并真机库和模拟器库的命令
- EJBCA与项目整合-第三章-EJBCA源码研究
- uses-permission权限汇总
- NSData按位取
- sphinx的安装篇