四分树

1013: 【模板】四分树(二维线段树 / 二维树状数组) 时间限制: 4 Sec 内存限制: 512 MB
提交: 4 解决: 2
[提交][状态][讨论版][命题人:stone41123][Edit] [TestData]
题目描述
给定一个n*m的矩阵,有q个操作,分为两种,分别为update和sum
对于每一个update,给出(x1,y1)为左上角坐标,(x2,y2)为右下角坐标,val为给这个区域加上val
对于每一个sum,给出(x1,y1)为左上角坐标,(x2,y2)为右下角坐标,输出区域的元素和
输入
第一行三个正整数,n,m,q
接下来n行,每行m个正整数,描述这个矩阵的初始值
接下来q行,每行描述一个操作,第一个数字为opt,当opt=1时为update,当opt=2时为sum
输出
对于每一个sum,输出其结果
样例输入
5 5 8
2 8 5 1 10
5 9 9 3 5
6 6 2 8 2
2 6 3 8 7
2 5 3 4 3
1 2 1 2 4 8
1 2 3 4 5 8
2 1 2 5 4
1 4 2 4 5 2
2 3 3 4 5
2 3 2 5 4
2 2 1 4 1
1 2 1 4 3 5
样例输出
152
84
83
21
提示
对于20%的数据,1<=n,m<=10,1<=q<=100
对于50%的数据,1<=n,m<=100,1<=q<=1000
对于70%的数据,1<=n,m<=500,1<=q<=20000
对于100%的数据,1<=n,m<=800,1<=q<=50000
保证答案不超过C++的long long,Pascal的int64
【四分树】随便搞了个板子题,然后尝试着写一下传说中的四分树,发现挺好写
就是莫名其妙四分树常数爆炸,开了4s才够,极限数据跑了3700ms左右
四分树就是用一个类似于线段树的东西来维护一个矩阵,就是每个点有四个儿子
然后每个儿子代表切分之后的一块区域,具体可以看我的代码
代码:

#include #include #include #include #include #include #define ll long long #define lu rt<<2 #define ld rt<<2|1 #define ru rt<<2|2 #define rd rt<<2|3 using namespace std; inline int read(){ int x=0; char ch=' '; int f=1; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')f=-1,ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f; } const int N=805,M=N*N*16; int n,m,q; ll sum[M],add[M],size[M],a[N][N]; inline void pushup(int rt){sum[rt]=sum[lu]+sum[ld]+sum[ru]+sum[rd]; } inline void pushdown(int rt){ if(add[rt]){ add[lu]+=add[rt]; sum[lu]+=size[lu]*add[rt]; add[ld]+=add[rt]; sum[ld]+=size[ld]*add[rt]; add[ru]+=add[rt]; sum[ru]+=size[ru]*add[rt]; add[rd]+=add[rt]; sum[rd]+=size[rd]*add[rt]; add[rt]=0; } } inline void build(int rt,int lx,int ly,int rx,int ry){ if(lx>rx||ly>ry)return; size[rt]=(rx-lx+1)*(ry-ly+1); if(lx==rx&&ly==ry){sum[rt]=a[lx][ly]; return; } int midx=(lx+rx)>>1,midy=(ly+ry)>>1; build(lu,lx,ly,midx,midy); build(ld,lx,midy+1,midx,ry); build(ru,midx+1,ly,rx,midy); build(rd,midx+1,midy+1,rx,ry); pushup(rt); } int X1,Y1,X2,Y2; ll val,ans; inline void update(int rt,int lx,int ly,int rx,int ry){ if(lx>rx||ly>ry)return; if(X1<=lx&&rx<=X2&&Y1<=ly&&ry<=Y2){add[rt]+=val; sum[rt]+=val*size[rt]; return; } pushdown(rt); int midx=(lx+rx)>>1,midy=(ly+ry)>>1; if(X1<=midx&&Y1<=midy)update(lu,lx,ly,midx,midy); if(X1<=midx&&midy+1<=Y2)update(ld,lx,midy+1,midx,ry); if(midx+1<=X2&&Y1<=midy)update(ru,midx+1,ly,rx,midy); if(midx+1<=X2&&midy+1<=Y2)update(rd,midx+1,midy+1,rx,ry); pushup(rt); } inline void query(int rt,int lx,int ly,int rx,int ry){ if(lx>rx||ly>ry)return; if(X1<=lx&&rx<=X2&&Y1<=ly&&ry<=Y2){ans+=sum[rt]; return; } pushdown(rt); int midx=(lx+rx)>>1,midy=(ly+ry)>>1; if(X1<=midx&&Y1<=midy)query(lu,lx,ly,midx,midy); if(X1<=midx&&midy+1<=Y2)query(ld,lx,midy+1,midx,ry); if(midx+1<=X2&&Y1<=midy)query(ru,midx+1,ly,rx,midy); if(midx+1<=X2&&midy+1<=Y2)query(rd,midx+1,midy+1,rx,ry); pushup(rt); } int main(){ n=read(); m=read(); q=read(); for(int i=1; i<=n; i++)for(int j=1; j<=m; j++)a[i][j]=read(); build(1,1,1,n,m); while(q--){ int opt=read(); X1=read(); Y1=read(); X2=read(); Y2=read(); if(opt==1)val=read(),update(1,1,1,n,m); else ans=0,query(1,1,1,n,m),printf("%lld\n",ans); } return 0; }

    推荐阅读