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

学到了关于线段树区间更新的不下传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对答案的修正是确实意义上永久奏效的

原文地址:https://www.cnblogs.com/Drenight/p/8611914.html