uva11992 - Fast Matrix Operations(含线段树模板)

链接

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值