链接
https://vjudge.net/problem/UVA-11992
题解
把矩阵展开变成一条线,然后就是线段树模板了
写题+调试一共用了51分57秒
好久不写确实是有些生疏了
代码
#include <bits/stdc++.h>
#define maxn 1000010
#define linf (1ll<<60)
using namespace std;
typedef long long ll;
struct segtree
{
segtree *lch, *rch;
ll l, r, set, add, max, min, sum;
}pool[maxn<<2], *root;
ll ndtot, R, C, M;
void pushdown(segtree *p)
{
if(p->set!=-1)
{
p->max=p->min=p->set;
p->sum=(p->r-p->l+1)*p->set;
if(p->lch)p->lch->add=p->rch->add=0, p->lch->set=p->rch->set=p->set;
p->set=-1;
}
if(p->add)
{
p->max+=p->add, p->min+=p->add;
p->sum+=(p->r-p->l+1)*p->add;
if(p->lch)p->lch->add+=p->add, p->rch->add+=p->add;
p->add=0;
}
}
void update(segtree *p)
{
pushdown(p->lch), pushdown(p->rch);
p->max=max(p->lch->max,p->rch->max);
p->min=min(p->lch->min,p->rch->min);
p->sum=p->lch->sum+p->rch->sum;
}
void build(segtree *p, ll l, ll r)
{
ll mid(l+r>>1);
p->l=l, p->r=r;
if(l==r)
{
p->lch=p->rch=NULL;
p->add=0;
p->set=-1;
p->min=p->max=p->sum=0;
return;
}
build(p->lch=pool+ ++ndtot,l,mid);
build(p->rch=pool+ ++ndtot,mid+1,r);
update(p);
p->set=-1;
}
void segset(segtree *p, ll l, ll r, ll set)
{
pushdown(p);
ll mid(p->l+p->r>>1);
if(l<=p->l and r>=p->r)
{
p->add=0;
p->set=set;
return;
}
if(l<=mid)segset(p->lch,l,r,set);
if(r>mid)segset(p->rch,l,r,set);
update(p);
}
void segadd(segtree *p, ll l, ll r, ll add)
{
pushdown(p);
ll mid(p->l+p->r>>1);
if(l<=p->l and r>=p->r)
{
p->add+=add;
return;
}
if(l<=mid)segadd(p->lch,l,r,add);
if(r>mid)segadd(p->rch,l,r,add);
update(p);
}
ll segsum(segtree *p, ll l, ll r)
{
pushdown(p);
ll mid(p->l+p->r>>1), ans(0ll);
if(l<=p->l and r>=p->r)return p->sum;
if(l<=mid)ans+=segsum(p->lch,l,r);
if(r>mid)ans+=segsum(p->rch,l,r);
return ans;
}
ll segmax(segtree *p, ll l, ll r)
{
pushdown(p);
ll mid(p->l+p->r>>1), ans(-linf);
if(l<=p->l and r>=p->r)return p->max;
if(l<=mid)ans=max(ans,segmax(p->lch,l,r));
if(r>mid)ans=max(ans,segmax(p->rch,l,r));
return ans;
}
ll segmin(segtree *p, ll l, ll r)
{
pushdown(p);
ll mid(p->l+p->r>>1), ans(linf);
if(l<=p->l and r>=p->r)return p->min;
if(l<=mid)ans=min(ans,segmin(p->lch,l,r));
if(r>mid)ans=min(ans,segmin(p->rch,l,r));
return ans;
}
ll read(ll x=0)
{
ll c, f=1;
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return f*x;
}
void init()
{
ndtot=0;
build(root = pool+ ++ndtot,1,R*C);
}
void solve()
{
ll x1, y1, x2, y2, type, v, l, r, mx, mn, sm;
while(M--)
{
type=read();
x1=read(), y1=read(), x2=read(), y2=read();
if(type!=3)v=read();
mx=-linf, mn=linf, sm=0;
for(auto i=x1;i<=x2;i++)
{
l=y1+(i-1)*C;
r=y2+(i-1)*C;
if(type==1)
{
segadd(root,l,r,v);
}
if(type==2)
{
segset(root,l,r,v);
}
if(type==3)
{
mx=max(mx,segmax(root,l,r));
mn=min(mn,segmin(root,l,r));
sm+=segsum(root,l,r);
}
}
if(type==3)
{
printf("%lld %lld %lld\n",sm,mn,mx);
}
}
}
int main()
{
while(~scanf("%lld%lld%lld",&R,&C,&M))
{
init();
solve();
}
return 0;
}
线段树模板
struct segtree
{
segtree *lch, *rch;
ll l, r, set, add, max, min, sum;
}pool[maxn<<2], *root;
ll ndtot;
void pushdown(segtree *p)
{
if(p->set!=-1)
{
p->max=p->min=p->set;
p->sum=(p->r-p->l+1)*p->set;
if(p->lch)p->lch->add=p->rch->add=0, p->lch->set=p->rch->set=p->set;
p->set=-1;
}
if(p->add)
{
p->max+=p->add, p->min+=p->add;
p->sum+=(p->r-p->l+1)*p->add;
if(p->lch)p->lch->add+=p->add, p->rch->add+=p->add;
p->add=0;
}
}
void update(segtree *p)
{
pushdown(p->lch), pushdown(p->rch);
p->max=max(p->lch->max,p->rch->max);
p->min=min(p->lch->min,p->rch->min);
p->sum=p->lch->sum+p->rch->sum;
}
void build(segtree *p, ll l, ll r)
{
ll mid(l+r>>1);
p->l=l, p->r=r;
if(l==r)
{
p->lch=p->rch=NULL;
p->add=0;
p->set=-1;
p->min=p->max=p->sum=0;
return;
}
build(p->lch=pool+ ++ndtot,l,mid);
build(p->rch=pool+ ++ndtot,mid+1,r);
update(p);
p->set=-1;
}
void segset(segtree *p, ll l, ll r, ll set)
{
pushdown(p);
ll mid(p->l+p->r>>1);
if(l<=p->l and r>=p->r)
{
p->add=0;
p->set=set;
return;
}
if(l<=mid)segset(p->lch,l,r,set);
if(r>mid)segset(p->rch,l,r,set);
update(p);
}
void segadd(segtree *p, ll l, ll r, ll add)
{
pushdown(p);
ll mid(p->l+p->r>>1);
if(l<=p->l and r>=p->r)
{
p->add+=add;
return;
}
if(l<=mid)segadd(p->lch,l,r,add);
if(r>mid)segadd(p->rch,l,r,add);
update(p);
}
ll segsum(segtree *p, ll l, ll r)
{
pushdown(p);
ll mid(p->l+p->r>>1), ans(0ll);
if(l<=p->l and r>=p->r)return p->sum;
if(l<=mid)ans+=segsum(p->lch,l,r);
if(r>mid)ans+=segsum(p->rch,l,r);
return ans;
}
ll segmax(segtree *p, ll l, ll r)
{
pushdown(p);
ll mid(p->l+p->r>>1), ans(-linf);
if(l<=p->l and r>=p->r)return p->max;
if(l<=mid)ans=max(ans,segmax(p->lch,l,r));
if(r>mid)ans=max(ans,segmax(p->rch,l,r));
return ans;
}
ll segmin(segtree *p, ll l, ll r)
{
pushdown(p);
ll mid(p->l+p->r>>1), ans(linf);
if(l<=p->l and r>=p->r)return p->min;
if(l<=mid)ans=min(ans,segmin(p->lch,l,r));
if(r>mid)ans=min(ans,segmin(p->rch,l,r));
return ans;
}
该模板能实现线段树区间
a
d
d
add
add、区间
s
e
t
set
set、区间查询最大、最小、和
由于
s
e
t
set
set以
−
1
-1
−1表示空操作,所以
s
e
t
set
set的值必须不能是负数
使用前要先build(root=pool+ ++ndtot),这样root就指向了线段树的根
查询最大值就x=segmax(root,l,r)