UVa 11992 Fast Matrix Operations(两种标记的线段树)

本题涉及到了线段数大多数基本操作。
因为只有20行,所以可以建20个线段树。
线段树最重要的两个函数:
pushdown 下移标记,并更新子节点数据。
pushup  由2个子节点数据更新父节点数据。


写法有很多,介绍一种不容易错的:
保证在设置标记的同时更新节点信息。即:在update给某节点打标记,以及pushdown下发标记时,都马上更新节点信息。
这样写的效果是pushup很短,直接更新,因为子节点的信息已经保证被更新过了,不需要考虑标记。相反在pushdown的时候要写很长,因为要直接更新子节点。


set操作会清空add标记。


代码:

//
//  main.cpp
//  11992 Fast Matrix Operations
//
//  Created by Baoli1100 on 15/3/14.
//  Copyright (c) 2015年 Baoli1100. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 800005
#define INF 1000000000
struct Tree{
    int Sum[maxn],Min[maxn],Max[maxn],add[maxn],Set[maxn];
    int sumr,minr,maxr;
    int op,y1,y2;
    void init(){
        memset(Sum,0,sizeof(Sum));
        memset(add,0,sizeof(add));
        memset(Set,-1,sizeof(Set));
        memset(Min,0,sizeof(Min));
        memset(Max,0,sizeof(Max));
    };
    void pushup(int rt){
        int lc=rt<<1,rc=rt<<1|1;
        Sum[rt]=Sum[lc]+Sum[rc];
        Min[rt]=min(Min[lc],Min[rc]);
        Max[rt]=max(Max[lc],Max[rc]);
    }
    void pushdown(int rt,int L,int R){
        int lc=rt<<1,rc=rt<<1|1;
        int M=(L+R)/2;
        if(Set[rt]>=0){
            Set[lc]=Set[rc]=Set[rt];
            add[lc]=add[rc]=0;
            Max[lc]=Max[rc]=Min[lc]=Min[rc]=Set[rt];
            Sum[lc]=(M-L+1)*Set[rt];
            Sum[rc]=(R-M)*Set[rt];
            Set[rt]=-1;
        }
        if(add[rt]){
            add[lc]+=add[rt];
            add[rc]+=add[rt];
            Max[lc]+=add[rt];Min[lc]+=add[rt];
            Max[rc]+=add[rt];Min[rc]+=add[rt];
            Sum[lc]+=add[rt]*(M-L+1);
            Sum[rc]+=add[rt]*(R-M);
            add[rt]=0;
        }
    }
    void update(int rt,int L,int R,int v){
        int lc=rt<<1,rc=rt<<1|1;
        int M=(L+R)/2;
        if(y1<=L&&y2>=R){
            if(op==1){
                add[rt]+=v;
                Sum[rt]+=v*(R-L+1);
                Max[rt]+=v;
                Min[rt]+=v;
            }
            else {
                Set[rt]=v;
                add[rt]=0;
                Max[rt]=Min[rt]=v;
                Sum[rt]=v*(R-L+1);
            }
        }
        else{
            pushdown(rt,L,R);
            if(y1<=M) update(lc,L,M,v);
            if(y2>M) update(rc,M+1,R,v);
            pushup(rt);
        }
    }
    void Query(int rt,int L,int R){
        int lc=rt<<1,rc=rt<<1|1;
        int M=(L+R)/2;
        if(y1<=L&&y2>=R){
            sumr+=Sum[rt];
            maxr=max(maxr,Max[rt]);
            minr=min(minr,Min[rt]);
            return;
        }
        else {
            pushdown(rt,L,R);
            if(y1<=M){
                Query(lc,L,M);
            }
            if(y2>M) Query(rc,M+1,R);
            pushup(rt);
        }
    }
}T[25];
int R,C,M;
int main(){
    while(~scanf("%d%d%d",&R,&C,&M)){
        for(int i=1;i<=R;i++){
            T[i].init();
        }
        int op,x1,x2,y1,y2,v;
        for(int i=1;i<=M;i++){
            scanf("%d",&op);
            if(op<3){
                scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&v);
                for(int i=x1;i<=x2;i++){
                    T[i].y1=y1;T[i].y2=y2;T[i].op=op;
                    T[i].update(1,1,C,v);
                }
            }
            else{
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                int rmin=INF,rmax=-INF,rsum=0;
                for(int i=x1;i<=x2;i++){
                    T[i].minr=INF;T[i].maxr=-INF;T[i].sumr=0;
                    T[i].y1=y1;T[i].y2=y2;
                    T[i].Query(1,1,C);
                    rmin=min(rmin,T[i].minr);
                    rmax=max(rmax,T[i].maxr);
                    rsum+=T[i].sumr;
                }
                printf("%d %d %d\n",rsum,rmin,rmax);
            }
        }
    }
    return 0;
}
/*
 3 3 111
 1 1 1 1 1 1
 3 1 1 1 1
 2 1 1 2 2 0
 3 1 1 1 1
 */


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值