uva11992 Fast Matrix Operations (线段树)

来源:互联网 发布:淘宝美工装修 编辑:程序博客网 时间:2024/05/23 12:32

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18697

题意:给定N*M的矩阵,初始值为0。有三种操作①将x1~x2行的y1~y2列的值加v(v>0)②将x1~x2行的y1~y2列的值改为v(v>0)③查询x1~x2行的y1~y2列里面的所有值的和,以及其中的最小值和最大值。(N<=20)

分析:由于N<20,只需维护N棵线段树就行了。我开始写的代码虽然A了,但是感觉不怎么好。后来又写了一个版本。


开始的版本:每次更新的时候只把当前区间的懒惰标记修改一下,本身的最大最小值以及和都没有更新,pushdown的时候也只把懒惰标记传递下去,所以查询的时候当前区间还要把左右孩子的信息传递上来。感觉有点危险。以后还是不要这样写。

代码:

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn = 1e6+6;int _max,_min,_sum;struct node{int setv,addv;int Max,Min,Sum;};struct segtree{node tree[maxn<<2];void build(int l,int r,int rt){tree[rt].addv=tree[rt].Max=tree[rt].Min=tree[rt].setv=tree[rt].Sum=0;if(l==r)return ;int m=(l+r)>>1;build(lson);build(rson);}void pushdown(int rt){if(tree[rt].setv>0){tree[rt<<1].setv=tree[rt<<1|1].setv=tree[rt].setv;tree[rt<<1].addv=tree[rt<<1|1].addv=tree[rt].setv=0;}if(tree[rt].addv>0){tree[rt<<1].addv+=tree[rt].addv;tree[rt<<1|1].addv+=tree[rt].addv;tree[rt].addv=0;}}void pushup(int l,int r,int rt){int m=(l+r)>>1,lmax,lmin,lsum,rmax,rmin,rsum;lmax=tree[rt<<1].addv+tree[rt<<1].Max;lmin=tree[rt<<1].addv+tree[rt<<1].Min;lsum=tree[rt<<1].Sum+tree[rt<<1].addv*(m-l+1);rmax=tree[rt<<1|1].addv+tree[rt<<1|1].Max;rmin=tree[rt<<1|1].addv+tree[rt<<1|1].Min;rsum=tree[rt<<1|1].Sum+tree[rt<<1|1].addv*(r-m);if(tree[rt<<1].setv>0){lmax=lmin=tree[rt<<1].setv+tree[rt<<1].addv;lsum=(tree[rt<<1].setv+tree[rt<<1].addv)*(m-l+1);}if(tree[rt<<1|1].setv>0){rmax=rmin=tree[rt<<1|1].setv+tree[rt<<1|1].addv;rsum=(tree[rt<<1|1].setv+tree[rt<<1|1].addv)*(r-m);}tree[rt].Max=max(lmax,rmax);tree[rt].Min=min(lmin,rmin);tree[rt].Sum=lsum+rsum;}void update_add(int L,int R,int v,int l,int r,int rt){if(L<=l && r<=R){tree[rt].addv+=v;return ;}pushdown(rt);int m=(l+r)>>1;if(L<=m)update_add(L,R,v,lson);if(R>m)update_add(L,R,v,rson);pushup(l,r,rt);}void update_set(int L,int R,int v,int l,int r,int rt){if(L<=l && r<=R){tree[rt].addv=0;tree[rt].setv=v;return ;}pushdown(rt);int m=(l+r)>>1;if(L<=m)update_set(L,R,v,lson);if(R>m)update_set(L,R,v,rson);pushup(l,r,rt);}void query(int L,int R,int l,int r,int rt){if(L<=l && r<=R){pushdown(rt);pushup(l,r,rt);if(tree[rt].Max>_max)_max=tree[rt].Max;if(tree[rt].Min<_min)_min=tree[rt].Min;_sum+=tree[rt].Sum;return ;}pushdown(rt);int m=(l+r)>>1;if(L<=m)query(L,R,lson);if(R>m)query(L,R,rson);pushup(l,r,rt);}}T[22];int main(){int N,n,q,tp,L,R,v,x,y;while(scanf("%d%d%d",&N,&n,&q)!=EOF){for(int i=0;i<=N;i++)T[i].build(1,n,1);while(q--){scanf("%d",&tp);if(tp==1){scanf("%d%d%d%d%d",&x,&L,&y,&R,&v);for(int i=x;i<=y;i++)T[i].update_add(L,R,v,1,n,1);}else if(tp==2){scanf("%d%d%d%d%d",&x,&L,&y,&R,&v);for(int i=x;i<=y;i++)T[i].update_set(L,R,v,1,n,1);}else{_min=2e9;_max=-_min;_sum=0;scanf("%d%d%d%d",&x,&L,&y,&R);for(int i=x;i<=y;i++)T[i].query(L,R,1,n,1);printf("%d %d %d\n",_sum,_min,_max);}}}return 0;}

后来的版本,更新的时候把当前区间的所有信息都更新了,pushdown的时候把左右孩子的所有信息更新了。所以查询的时候直接用当前区间的信息。

代码:

#include <iostream>#include <cstdio>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn = 1e6+6;int _min,_max,_sum;struct node{int addv,setv;int Max,Min,Sum;};struct segtree{node tree[maxn<<2];void pushdown(int l,int r,int rt){int m=(l+r)>>1;if(tree[rt].setv>0){tree[rt<<1].Max=tree[rt<<1|1].Max=tree[rt<<1].Min=tree[rt<<1|1].Min=tree[rt<<1].setv=tree[rt<<1|1].setv=tree[rt].setv;tree[rt<<1].Sum=tree[rt].setv*(m-l+1);tree[rt<<1|1].Sum=tree[rt].setv*(r-m);tree[rt<<1].addv=tree[rt<<1|1].addv=tree[rt].setv=0;}if(tree[rt].addv>0){tree[rt<<1].addv+=tree[rt].addv;tree[rt<<1].Max+=tree[rt].addv;tree[rt<<1].Min+=tree[rt].addv;tree[rt<<1].Sum+=tree[rt].addv*(m-l+1);tree[rt<<1|1].addv+=tree[rt].addv;tree[rt<<1|1].Max+=tree[rt].addv;tree[rt<<1|1].Min+=tree[rt].addv;tree[rt<<1|1].Sum+=tree[rt].addv*(r-m);tree[rt].addv=0;}}void pushup(int rt){tree[rt].Max=max(tree[rt<<1].Max,tree[rt<<1|1].Max);tree[rt].Min=min(tree[rt<<1].Min,tree[rt<<1|1].Min);tree[rt].Sum=tree[rt<<1].Sum+tree[rt<<1|1].Sum;}void build(int l,int r,int rt){tree[rt].Max=tree[rt].Min=tree[rt].addv=tree[rt].setv=tree[rt].Sum=0;if(l==r)return ;int m=(l+r)>>1;build(lson);build(rson);}void update_add(int L,int R,int v,int l,int r,int rt){if(L<=l && r<=R){tree[rt].addv+=v;tree[rt].Sum+=v*(r-l+1);tree[rt].Max+=v;tree[rt].Min+=v;return ;}pushdown(l,r,rt);int m=(l+r)>>1;if(L<=m)update_add(L,R,v,lson);if(R>m)update_add(L,R,v,rson);pushup(rt);}void update_set(int L,int R,int v,int l,int r,int rt){if(L<=l && r<=R){tree[rt].addv=0;tree[rt].setv=v;tree[rt].Sum=v*(r-l+1);tree[rt].Max=v;tree[rt].Min=v;return ;}pushdown(l,r,rt);int m=(l+r)>>1;if(L<=m)update_set(L,R,v,lson);if(R>m)update_set(L,R,v,rson);pushup(rt);}void query(int L,int R,int l,int r,int rt){if(L<=l && r<=R){_sum+=tree[rt].Sum;if(tree[rt].Min<_min)_min=tree[rt].Min;if(tree[rt].Max>_max)_max=tree[rt].Max;return ;}pushdown(l,r,rt);int m=(l+r)>>1;if(L<=m)query(L,R,lson);if(R>m)query(L,R,rson);pushup(rt);}}T[22];int main(){int N,n,q,tp,L,R,v,x,y;while(scanf("%d%d%d",&N,&n,&q)!=EOF){for(int i=0;i<=N;i++)T[i].build(1,n,1);while(q--){scanf("%d",&tp);if(tp==1){scanf("%d%d%d%d%d",&x,&L,&y,&R,&v);for(int i=x;i<=y;i++)T[i].update_add(L,R,v,1,n,1);}else if(tp==2){scanf("%d%d%d%d%d",&x,&L,&y,&R,&v);for(int i=x;i<=y;i++)T[i].update_set(L,R,v,1,n,1);}else{_min=2e9;_max=-_min;_sum=0;scanf("%d%d%d%d",&x,&L,&y,&R);for(int i=x;i<=y;i++)T[i].query(L,R,1,n,1);printf("%d %d %d\n",_sum,_min,_max);}}}return 0;}


0 0
原创粉丝点击