https://vjudge.net/problem/UVA-11992
题意:给定一个矩阵,最多20行,最多1e6列。给定m次操作,每次給一个矩形加值或覆盖一个值,或者查询矩形元素和。
思路:《训练指南》的例题。
20行,那就开20个线段树,每个维护一行,同时有setv和addv的标记,那么规定:先执行setv,再执行addv。每次setv修改时,都修改addv为0。注意懒标记的下传和维护即可。
#include<bits/stdc++.h>
using namespace std;
#define maxn (1000000+100)
int r,c,m;
int ql,qr,val,op;
struct SegmentTree{
int addv[maxn*4],setv[maxn*4],sumv[maxn*4],minv[maxn*4],maxv[maxn*4];
int _sum,_min,_max;
void init(){_sum=0;_min=(1<<30);_max=0;}
void maintain(int o,int l,int r)
{
if(setv[o]!=-1)
{
sumv[o]=setv[o]*(r-l+1);
minv[o]=maxv[o]=setv[o];
}
else
{
sumv[o]=sumv[o*2]+sumv[o*2+1];
minv[o]=min(minv[o*2],minv[o*2+1]);
maxv[o]=max(maxv[o*2],maxv[o*2+1]);
}
sumv[o]+=addv[o]*(r-l+1);
minv[o]+=addv[o];
maxv[o]+=addv[o];
}
void pushdown(int o)
{
if(setv[o]!=-1)
{
setv[o*2]=setv[o*2+1]=setv[o];
addv[o*2]=addv[o*2+1]=0;
setv[o]=-1;
}
if(addv[o]!=0)
{
addv[o*2]+=addv[o];
addv[o*2+1]+=addv[o];
addv[o]=0;
}
}
void update(int o,int l,int r)
{
if(ql<=l&&qr>=r)
{
if(op==2){setv[o]=val;addv[o]=0;}
else addv[o]+=val;
}
else
{
int mid=(l+r)/2;
pushdown(o);
if(ql<=mid)update(o*2,l,mid);else maintain(o*2,l,mid);
if(qr>mid)update(o*2+1,mid+1,r);else maintain(o*2+1,mid+1,r);
}
maintain(o,l,r);
}
void query(int o,int l,int r)
{
if(ql<=l&&qr>=r)
{
_sum+=sumv[o];
_min=min(_min,minv[o]);
_max=max(_max,maxv[o]);
}
else
{
int mid=(l+r)/2;
pushdown(o);
maintain(o*2,l,mid);maintain(o*2+1,mid+1,r);
maintain(o,l,r);
if(ql<=mid)query(o*2,l,mid);
if(qr>mid)query(o*2+1,mid+1,r);
}
}
};
SegmentTree tree[25];
int main()
{
//freopen("input.in","r",stdin);
int r1,r2;
while(cin>>r>>c>>m)
{
for(int i=1;i<=20;i++)tree[i].setv[1]=tree[i].addv[1]=0,tree[i].maintain(1,1,c);
while(m--)
{
scanf("%d%d%d%d%d",&op,&r1,&ql,&r2,&qr);
if(op!=3)
{
scanf("%d",&val);
for(int i=r1;i<=r2;i++)tree[i].update(1,1,c);
}
else
{
long long ans1=0;
int ans2=(1<<30),ans3=0;
for(int i=r1;i<=r2;i++)
{
tree[i].init();
tree[i].query(1,1,c);
ans1+=tree[i]._sum;
ans2=min(ans2,tree[i]._min);
ans3=max(ans3,tree[i]._max);
}
printf("%lld %d %d\n",ans1,ans2,ans3);
}
}
}
return 0;
}