• 线段树的标记永久化/二维线段树模板


    学到了关于线段树区间更新的不下传lazy标记的写法,

    应用在树套树比方说二维线段树这种,跨树传递lazy标记比较繁琐的地方可以很大的简化代码

    ---------------------------------------------------------------------------------------------------------------------

    ①首先是区间加值,区间求和的板子

    节点维护:区间和,区间标记

    update时,把路径上每个节点的值都加上(b-a+1)*val,到达目标节点的时候给节点打上标记

    query时,另开一个参数计数器累计路径节点上的标记值,到达目标区间的子区间时,返回子区间和+子区间长度*祖先们的标记和

    例题poj3468,link

    const int maxn=1e5+33;
    int n,m;
    ll a[maxn];
    
    ll val[maxn<<2],tag[maxn<<2];
    
    void build(int l,int r,int rt){
        if(l==r){val[rt]=a[l];return;}
        int m=l+r>>1;build(l,m,rt<<1);build(m+1,r,rt<<1|1);
        val[rt]=val[rt<<1]+val[rt<<1|1];
    }
    void update(int a,int b,ll c,int l,int r,int rt){
        val[rt]+=c*(b-a+1);
        if(l==a && r==b){
            tag[rt]+=c;return;
        }
        int m=l+r>>1;
        if(b<=m)update(a,b,c,l,m,rt<<1);
        else{
            if(a>m)update(a,b,c,m+1,r,rt<<1|1);
            else{
                update(a,m,c,l,m,rt<<1);
                update(m+1,b,c,m+1,r,rt<<1|1);
            }
        }
    }
    ll query(int a,int b,ll ad,int l,int r,int rt){
        if(a==l && b==r){return val[rt]+ad*(b-a+1);}
        int m=l+r>>1;
        ll ret=0;
        if(b<=m)return query(a,b,ad+tag[rt],l,m,rt<<1);
        else{
            if(a>m)return query(a,b,ad+tag[rt],m+1,r,rt<<1|1);
            else return
                query(a,m,ad+tag[rt],l,m,rt<<1)
                    +
                query(m+1,b,ad+tag[rt],m+1,r,rt<<1|1);
        }
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        build(1,n,1);
    
        while(m--){
            char ch[2];int x,y,z;
            scanf("%s",ch);
            if(ch[0]=='Q'){
                scanf("%d%d",&x,&y);
                printf("%lld
    ",query(x,y,0,1,n,1));
            }
            else{scanf("%d%d%d",&x,&y,&z);update(x,y,z,1,n,1);}
        }
    }
    View Code

     ②区间加值,求区间最值  (二维下仅限加值全部同号)

    节点维护:区间最值,区间标记

    update时,先查询目标节点的原值,然后把value设置为这个原值加上要加的值,再update

    沿路用value更新节点值,val[cur]=max(val[cur],value),这就省去了pushup操作

    到达目标节点时,tag[cur]=max(tag[cur],value)更新目标节点的标记

    query时,每路过一个节点都要用它的tag来更新答案,这些tag是历史某时刻子树的最大值

    例题洛谷3437

      1 //#include<bits/stdc++.h>  
      2 //#pragma comment(linker, "/STACK:1024000000,1024000000")   
      3 #include<stdio.h>  
      4 #include<algorithm>  
      5 #include<queue>  
      6 #include<string.h>  
      7 #include<iostream>  
      8 #include<math.h>                    
      9 #include<stack>
     10 #include<set>  
     11 #include<map>  
     12 #include<vector>  
     13 #include<iomanip> 
     14 #include<bitset>
     15 using namespace std;         //
     16 
     17 #define ll long long  
     18 #define ull unsigned long long
     19 #define pb push_back  
     20 #define FOR(a) for(int i=1;i<=a;i++) 
     21 #define sqr(a) (a)*(a)
     22 #define dis(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))
     23 ll qp(ll a,ll b,ll mod){
     24     ll t=1;while(b){if(b&1)t=t*a%mod;b>>=1;a=a*a%mod;}return t;
     25 }
     26 struct DOT{int x;int y;};
     27 //inline void read(int &x){int k=0;char f=1;char c=getchar();for(;!isdigit(c);c=getchar())if(c=='-')f=-1;for(;isdigit(c);c=getchar())k=k*10+c-'0';x=k*f;} 
     28 void ex(){puts("-1");exit(0);}
     29 const int dx[4]={0,0,-1,1};
     30 const int dy[4]={1,-1,0,0};
     31 const int inf=0x3f3f3f3f; 
     32 const ll Linf=0x3f3f3f3f3f3f3f3f;
     33 const ll mod=1e9+7;;
     34 
     35 const int maxn=1005*4;
     36 
     37 /******************************************************/  
     38 namespace fastIO{    
     39     #define BUF_SIZE 100000    
     40     #define OUT_SIZE 100000    
     41     #define ll long long    
     42     //fread->read    
     43     bool IOerror=0;    
     44     inline char nc(){    
     45         static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;    
     46         if (p1==pend){    
     47             p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);    
     48         if (pend==p1){IOerror=1;return -1;}    
     49         //{printf("IO error!
    ");system("pause");for (;;);exit(0);}    
     50     }    
     51     return *p1++;    
     52 }    
     53 inline bool blank(char ch){return ch==' '||ch=='
    '||ch=='
    '||ch=='	';}    
     54 inline void read(int &x){    
     55     bool sign=0; char ch=nc(); x=0;    
     56     for (;blank(ch);ch=nc());    
     57     if (IOerror)return;    
     58     if (ch=='-')sign=1,ch=nc();    
     59     for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';    
     60     if (sign)x=-x;    
     61 }    
     62 inline void read(ll &x){    
     63     bool sign=0; char ch=nc(); x=0;    
     64     for (;blank(ch);ch=nc());    
     65     if (IOerror)return;    
     66     if (ch=='-')sign=1,ch=nc();    
     67     for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';    
     68     if (sign)x=-x;    
     69 }    
     70 inline void read(double &x){    
     71     bool sign=0; char ch=nc(); x=0;    
     72     for (;blank(ch);ch=nc());    
     73     if (IOerror)return;    
     74     if (ch=='-')sign=1,ch=nc();    
     75     for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';    
     76     if (ch=='.'){    
     77         double tmp=1; ch=nc();    
     78         for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');    
     79     }    
     80     if (sign)x=-x;    
     81 }    
     82 inline void read(char *s){    
     83     char ch=nc();    
     84     for (;blank(ch);ch=nc());    
     85     if (IOerror)return;    
     86     for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch;    
     87     *s=0;    
     88 }    
     89 inline void read(char &c){    
     90     for (c=nc();blank(c);c=nc());    
     91     if (IOerror){c=-1;return;}    
     92 }   
     93 #undef OUT_SIZE    
     94 #undef BUF_SIZE    
     95 }; using namespace fastIO;  
     96 /*****************************************************/  
     97 
     98 int D,S;
     99 
    100 struct inNODE{
    101     int val[maxn],tag[maxn];
    102     void update(int cur,int l,int r,int y1,int y2,int value){
    103         val[cur]=max(val[cur],value);
    104         if(y1<=l && r<=y2){
    105             tag[cur]=max(tag[cur],value);
    106         }else{
    107             int m=l+r>>1;
    108             if(y1<=m)update(cur<<1,l,m,y1,y2,value);
    109             if(y2>m)update(cur<<1|1,m+1,r,y1,y2,value);
    110         }
    111     }
    112     int query(int cur,int l,int r,int y1,int y2){
    113         if(y1<=l&&y2>=r)return val[cur];
    114         int m=l+r>>1;
    115         int res=tag[cur];
    116         if(y1<=m)res=max(res,query(cur<<1,l,m,y1,y2));
    117         if(y2>m)res=max(res,query(cur<<1|1,m+1,r,y1,y2));
    118         return res;
    119     }
    120 };
    121 struct outNODE{
    122     inNODE val[maxn],tag[maxn];
    123     void update(int cur,int l,int r,int x1,int x2,int y1,int y2,int value){
    124         val[cur].update(1,1,S,y1,y2,value);
    125         if(x1<=l&&x2>=r){
    126             tag[cur].update(1,1,S,y1,y2,value);
    127         }else{
    128             int m=l+r>>1;
    129             if(x1<=m)update(cur<<1,l,m,x1,x2,y1,y2,value);
    130             if(x2>m)update(cur<<1|1,m+1,r,x1,x2,y1,y2,value);
    131         }
    132     }
    133     int query(int cur,int l,int r,int x1,int x2,int y1,int y2){
    134         if(x1<=l&&x2>=r)return val[cur].query(1,1,S,y1,y2);
    135         int m=l+r>>1;
    136         int res=tag[cur].query(1,1,S,y1,y2);
    137         if(x1<=m)res=max(res,query(cur<<1,l,m,x1,x2,y1,y2));
    138         if(x2>m)res=max(res,query(cur<<1|1,m+1,r,x1,x2,y1,y2));
    139         return res;
    140     }
    141 }tree;
    142 
    143 int main(){
    144     //scanf("%d%d",&D,&S);
    145     read(D);read(S);
    146     int n;read(n);++D;++S;
    147     for(int i=1;i<=n;++i){
    148         int d,s,w,x,y;//scanf("%d%d%d%d%d",&d,&s,&w,&x,&y);
    149         read(d);read(s);read(w);read(x);read(y);
    150         ++x;++y;
    151         int tmp=tree.query(1,1,D,x,x+d-1,y,y+s-1);
    152         tree.update(1,1,D,x,x+d-1,y,y+s-1,tmp+w);
    153     }
    154     printf("%d
    ",tree.query(1,1,D,1,D,1,S));
    155     return 0;
    156 }
    View Code

     关于为什么必须同号可以看这组样例

    5 5 3

    2 5 2 0 0

    3 5 2 0 0

    5 5 -2 0 0

    显然由于tag存储的最值是老版本的,很有可能子树所有信息都被劣化了,这个tag却一直悬在这

    而区间求和就没这个问题,因为那时候的tag对答案的修正是确实意义上永久奏效的

  • 相关阅读:
    XidianOJ 1073 Nunchakus
    XidianOJ 1024 2的幂次表示
    XidianOJ 1072 National Disaster
    XidianOJ 1093 一元三次方程
    中国剩余定理
    bzoj2818(欧拉函数递推)
    poj2311(博弈论,sg函数)
    contesthunter#46-A(分块)
    Tree,点分治
    poj3580(splay 毒瘤题)
  • 原文地址:https://www.cnblogs.com/Drenight/p/8611914.html
Copyright © 2020-2023  润新知