Codeforces Round #439 (Div. 2) E. The Untended Antiquity 二维线段树||二维树状数组

来源:互联网 发布:网络传销崩盘前兆 编辑:程序博客网 时间:2024/06/05 23:39

http://codeforces.com/contest/869/problem/E

题意:n*m的矩阵,q次操作,三种类型

类型1:给指定矩阵加上围栏

类型2:给指定矩阵去掉围栏

类型3:查询两点是否存在一条不通过围栏的路

加围栏是全包,也就相当于加了围栏后只能是里面走向里面,外面走向外面,这样就可以给这块平面附一个值,判断能不能走直接判相等就可以了,因为有矩阵叠加的情况,也就是围栏里面加围栏,所以就要平面加值,不能平面替换值。为了防止叠加之后值相同,所以要加一个hash操作。

顺便总结下刚学的二维线段树

1:四叉树写法,感觉这种写法很坑,一旦有区间操作复杂度就不合理,虽然写起来简单,还可以加lazy标记,但感觉没什么用,只有查询最值可能好使一些,

简单说下自己想到的这种写法遇到区间操作复杂度不合理的情况,四叉树每次都要分成四个部分,可以想成四个方块,假如某个查询是查询一块长L很大,宽W很小的区域,为了符合L,必须要分的很小,递归深度很深,也就是说查询块被分成了很多个叠在一起的方块,而较优的查询(树套树写法)是对每一个维度都是类似的线段树分割,也就是说查询块被分成了几个叠在一起的不等长的长块。

2:线段树套线段树写法,只能实现区间更新单点查询或单点更新区间查询,因为第一维线段树无法使用lazy标记(目前没搜到如何使用。。。),局限了只能区间查询,区间更新单点查询里的区间更新也是伪区间更新,用了一个标记永久化的操作,更新的部分不往下放,查询一个点需要考虑他的所有祖先,因此局限了只能单点查询。


二维树状数组

单点更新区间查询是最基本的,也可以实现一些区间更新单点查询,例如本题,我要给某块平面(x1,y1,x2,y2)加k

就像伪线段区间更新一样,左端点加加,右端点减减,每个点对应值为前缀和值,平面依旧可以这样做

(x1,y1)+=k;

(x1,y2+1)-=k;

(x2+1,y1)-=k;

(x2+1,y2+1)+=k;

这样某个点(x,y)对应值应该是矩阵(1,1,x,y)的所有值的和,二维树状数组很容易求


二维线段树(389ms):

#include<bits/stdc++.h>using namespace std;const int maxn=2505;const unsigned long long mo=998244353;const unsigned long long zero=0;unsigned long long seg[maxn*2][maxn*2];int L,R,T,B,n,m;int X,Y;unsigned long long k;inline int id(int le,int ri){return le+ri|le!=ri;}void updatey(int le,int ri,int nodex){int nodey=id(le,ri);if(le>=T&&ri<=B){seg[nodex][nodey]+=k;return ;}int mid=(le+ri)>>1;if(T<=mid)updatey(le,mid,nodex);if(B>mid)updatey(mid+1,ri,nodex);}void updatex(int le,int ri){int node=id(le,ri);if(le>=L&&ri<=R){updatey(1,m,node);return ;}int mid=(le+ri)>>1;if(L<=mid)updatex(le,mid);if(R>mid)updatex(mid+1,ri);}unsigned long long queryy(int nodex,int le,int ri){int nodey=id(le,ri);if(le==ri){return seg[nodex][nodey];}unsigned long long ans=seg[nodex][nodey];int mid=(le+ri)>>1;if(Y<=mid)return ans+queryy(nodex,le,mid);elsereturn ans+queryy(nodex,mid+1,ri);}unsigned long long queryx(int le,int ri){int node=id(le,ri);if(le==ri){return queryy(node,1,m);}unsigned long long ans=queryy(node,1,m);int mid=(le+ri)>>1;if(X<=mid)return ans+queryx(le,mid);elsereturn ans+queryx(mid+1,ri);}unsigned long long hashh(unsigned long long n,unsigned long long m,int le,int ri,int to,int bo){unsigned long long temp1=(le*n+ri)*m*m;unsigned long long temp2=to*m+bo;return temp1+temp2;}int main(){int q,i,c;unsigned long long temp;cin>>n>>m>>q;while(q--){scanf("%d %d %d %d %d",&c,&L,&T,&R,&B);if(c==3){X=L,Y=T;unsigned long long flog1=queryx(1,n);X=R,Y=B;unsigned long long flog2=queryx(1,n);//cout<<flog1<<" "<<flog2<<endl;if(flog1!=flog2){printf("No\n");}else{printf("Yes\n");}}else{if(L>R)swap(L,R);if(T>B)swap(T,B);if(c==1)k=hashh(n,m,L,T,R,B);elsek=zero-hashh(n,m,L,T,R,B);updatex(1,n);}}return 0; }


二维树状数组(140ms):

#include<bits/stdc++.h>using namespace std;const int maxn=2505;const unsigned long long zero=0;int L,R,T,B,n,m;unsigned long long f[maxn][maxn],k;void add(int x,int y,unsigned long long k){    while(x<=n)    {        int ty=y;        while(ty<=m)        {            f[x][ty]+=k;            ty+=ty&-ty;        }        x+=x&-x;    }    return ;}unsigned long long sum(int x,int y){    unsigned long long ans=0;    while(x)    {        int ty=y;        while(ty)        {            ans+=f[x][ty];            ty-=ty&-ty;        }        x-=x&-x;    }    return ans;}void update(){    add(L,T,k);    add(R+1,T,zero-k);    add(L,B+1,zero-k);    add(R+1,B+1,k);}unsigned long long hashh(unsigned long long n,unsigned long long m,int le,int ri,int to,int bo){unsigned long long temp1=(le*n+ri)*m*m;unsigned long long temp2=to*m+bo;return temp1+temp2;}int main(){int q,i,c;unsigned long long temp;cin>>n>>m>>q;while(q--){scanf("%d %d %d %d %d",&c,&L,&T,&R,&B);if(c==3){unsigned long long flog1=sum(L,T);unsigned long long flog2=sum(R,B);//cout<<flog1<<" "<<flog2<<endl;if(flog1!=flog2){printf("No\n");}else{printf("Yes\n");}}else{if(L>R)swap(L,R);if(T>B)swap(T,B);if(c==1)k=hashh(n,m,L,T,R,B);elsek=zero-hashh(n,m,L,T,R,B);update();}}return 0; }

不得不说树状数组既简单,速度还优。。。。


顺便贴一个四叉树写法TLE代码,可能写的不太优雅,自带常数,但自己跑数据试了试,复杂度差的绝不是常数(仅针对下面代码)。。。。。

也可能是自己对四叉树写法理解的还不太深入。。。。。。。。

#include<bits/stdc++.h>#define ltson le,wm,to,hm#define lbson le,wm,hm+1,bo#define rtson wm+1,ri,to,hm#define rbson wm+1,ri,hm+1,bo#define son(x) node*4-2+x using namespace std;const int maxn=2505;const unsigned long long mo=998244353;const unsigned long long zero=0;unsigned long long seg[maxn*maxn*4];unsigned long long lazy[maxn*maxn*4];int L,R,T,B;int X,Y;unsigned long long area(int le,int ri,int to,int bo){return (ri-le+1)*(bo-to+1); }void pushdown(int node,int le,int ri,int to,int bo){if(lazy[node]){int wm=(le+ri)>>1,hm=(to+bo)>>1;unsigned long long t;t=area(le,wm,to,hm);seg[son(0)]+=t*lazy[node];t=area(le,wm,hm+1,bo);seg[son(1)]+=t*lazy[node];t=area(wm+1,ri,to,hm);seg[son(2)]+=t*lazy[node];t=area(wm+1,ri,hm+1,bo);seg[son(3)]+=t*lazy[node];lazy[son(0)]+=lazy[node];lazy[son(1)]+=lazy[node];lazy[son(2)]+=lazy[node];lazy[son(3)]+=lazy[node];lazy[node]=0;}return ;}void pushup(int node){seg[node]=seg[son(0)]+seg[son(1)]+seg[son(2)]+seg[son(3)];return ;}void update(unsigned long long k,int le,int ri,int to,int bo,int node){if(le>ri||to>bo)return ;//cout<<le<<" "<<ri<<" "<<to<<" "<<bo<<endl; if(le>=L&&ri<=R&&to>=T&&bo<=B){unsigned long long t=area(le,ri,bo,to);lazy[node]+=k;seg[node]+=t*k;return ; }pushdown(node,le,ri,to,bo);int wm=(le+ri)>>1,hm=(to+bo)>>1;if(L<=wm){if(T<=hm)update(k,ltson,son(0));if(B>hm)update(k,lbson,son(1));}if(R>wm){if(T<=hm)update(k,rtson,son(2));if(B>hm)update(k,rbson,son(3));}pushup(node);}unsigned long long query(int le,int ri,int to,int bo,int node){if(le==ri&&to==bo){return seg[node];}pushdown(node,le,ri,to,bo);int wm=(le+ri)>>1,hm=(to+bo)>>1;if(wm>=X){if(hm>=Y)return query(ltson,son(0));elsereturn query(lbson,son(1));}else{if(hm>=Y)return query(rtson,son(2));elsereturn query(rbson,son(3));} }unsigned long long hashh(unsigned long long n,unsigned long long m,int le,int ri,int to,int bo){unsigned long long temp1=(le*n+ri)*m*m;unsigned long long temp2=to*m+bo;return temp1+temp2;}int main(){int n,m,q,i,c;unsigned long long temp;cin>>n>>m>>q;while(q--){scanf("%d %d %d %d %d",&c,&L,&T,&R,&B);if(c==3){X=L,Y=T;unsigned long long flog1=query(1,n,1,m,1);X=R,Y=B;unsigned long long flog2=query(1,n,1,m,1);//cout<<flog1<<" "<<flog2<<endl;if(flog1!=flog2){printf("No\n");}else{printf("Yes\n");}}else{if(L>R)swap(L,R);if(T>B)swap(T,B);if(c==1){update(hashh(n,m,L,T,R,B),1,n,1,m,1);}else{update(zero-hashh(n,m,L,T,R,B),1,n,1,m,1);}}}return 0; } 




阅读全文
0 0