学到了关于线段树区间更新的不下传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);} } }
②区间加值,求区间最值 (二维下仅限加值全部同号)
节点维护:区间最值,区间标记
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 }
关于为什么必须同号可以看这组样例
5 5 3
2 5 2 0 0
3 5 2 0 0
5 5 -2 0 0
显然由于tag存储的最值是老版本的,很有可能子树所有信息都被劣化了,这个tag却一直悬在这
而区间求和就没这个问题,因为那时候的tag对答案的修正是确实意义上永久奏效的