题目: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|1
const 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|1
const 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;
}