UVA11992 线段树

因为行数最多20行,所以可以每行建造一颗线段树
update时 set操作要清除add标记
但add操作不需要清楚set标记
maintain函数(用于维护节点)先考虑set再考虑add
query操作要综合考虑add和set
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#include<vector>

using namespace std;
const int maxn=4e5+10;

int r,c,m,ql,qr;
const int INF=1000000000;
int _min,_max,_sum;
struct intervalTree
{
    int addv[maxn],setv[maxn],sum[maxn],minv[maxn],maxv[maxn];
    void maintain(int node,int l,int r)
    {
        int lc=node<<1,rc=node<<1|1;
     //   sum[node]=minv[node]=maxv[node]=0;
        if(r>l) {
            sum[node]=sum[lc]+sum[rc];
            minv[node]=min(minv[lc],minv[rc]);
            maxv[node]=max(maxv[lc],maxv[rc]);
        }
        if(setv[node]>=0){
            minv[node]=maxv[node]=setv[node];
            sum[node]=setv[node]*(r-l+1);
        }
        if(addv[node]) {
            minv[node]+=addv[node];
            maxv[node]+=addv[node];
            sum[node]+=addv[node]*(r-l+1);
        }
    }
    void pushdown(int node)
    {
        int lc=node<<1,rc=node<<1|1;
        if(setv[node]>=0) {
            setv[lc]=setv[rc]=setv[node];
            addv[lc]=addv[rc]=0;
            setv[node]=-1;
        }
        if(addv[node]>0) {
            addv[lc]+=addv[node];
            addv[rc]+=addv[node];
            addv[node]=0;
        }
    }
    void updateset(int node,int l,int r,int v)
    {
        int lc=node<<1,rc=node<<1|1;
        if(ql<=l&&qr>=r) {
            setv[node]=v;
            addv[node]=0;
        }
        else {
            pushdown(node);
            int m=l+(r-l)/2;
            if(ql<=m) updateset(lc,l,m,v);
            else maintain(lc,l,m);
            if(qr>m) updateset(rc,m+1,r,v);
            else maintain(rc,m+1,r);
        }
        maintain(node,l,r);
    }
    void updateadd(int node,int l,int r,int v)
    {
         int lc=node<<1,rc=node<<1|1;
        if(ql<=l&&qr>=r) {
            addv[node]+=v;
        }
        else {
            pushdown(node);
            int m=l+(r-l)/2;
            if(ql<=m) updateadd(lc,l,m,v);
            else maintain(lc,l,m);
            if(qr>m) updateadd(rc,m+1,r,v);
            else maintain(rc,m+1,r);
        }
        maintain(node,l,r);
    }
    void query(int node,int l,int r,int add)
    {
        if(setv[node]>=0) {
            int v=add+addv[node]+setv[node];
            _sum+=(min(qr,r)-max(l,ql)+1)*v;
            _min=min(_min,v);
            _max=max(_max,v);
        }
        else if(ql<=l&&qr>=r) {
            _sum+=sum[node]+add*(r-l+1);
            _min=min(_min,minv[node]+add);
            _max=max(_max,maxv[node]+add);
        }
        else {
            int m=l+(r-l)/2;
            if(ql<=m)
            query(node<<1,l,m,add+addv[node]);
            if(qr>m)
            query(node<<1|1,m+1,r,add+addv[node]);
        }

    }

};
intervalTree tree[25];
int main()
{
   // freopen("in.txt","r",stdin);
   // freopen("out.txt","w",stdout);
    while(scanf("%d%d%d",&r,&c,&m)!=EOF) {
        memset(tree,0,sizeof tree);
        for(int i = 1; i <= r;++i) {
            memset(tree[i].setv, -1, sizeof(tree[i].setv));
            tree[i].setv[1] = 0;
        }
        int op,x1,x2,v;
        while(m--) {
            _sum=0;
            _min=INF;
            _max=0;
            scanf("%d%d%d%d%d",&op,&x1,&ql,&x2,&qr);
            //if(x1>x2) swap(x1,x2);
            if(op==1||op==2) {
                scanf("%d",&v);
                if(op==1) {
                    for(int i = x1;i<=x2;++i) {
                        tree[i].updateadd(1,1,c,v);
                    }
                }
                else {
                     for(int i = x1;i<=x2;++i) {
                        tree[i].updateset(1,1,c,v);
                    }
                }
            }
            else {
                for(int i=x1;i<=x2;++i) {
                    tree[i].query(1,1,c,0);
                }
                printf("%d %d %d\n",_sum,_min,_max);

            }
        }
    }
    return 0;
}




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值