Luogu5280 [ZJOI2019] 线段树 线段树
Posted menhera
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu5280 [ZJOI2019] 线段树 线段树相关的知识,希望对你有一定的参考价值。
题目分析:
这题除了分类讨论就没啥了。。。
容易发现问题实际就是所有操作选和不选按顺序执行的所有答案和。考虑每个点在多少种情况下会有tag。
那么,考虑新插入一个[l,r],所有有交集的点都会被清空,所以这些点答案不变。
然后考虑有交集的点中间[l‘,r‘]是子集关系的点,这些点答案并不是不变,而是答案加了$2^{cnt-1}$,$cnt$为已执行的1操作数。
然后没被遍历到的点答案*2.
然后遍历到的点中间没有任何交集的点,答案数加的就是前面的操作方案中他到根的路径中间有tag的这个点的数量。
这个我们再建一个线段树,然后分类讨论。
对于扫到的终点和它下面的点,答案加上$2^{cnt-1}$,对于经过的有交集的点,答案不变。对于剩下遍历到的点和没遍历到的点,答案*2。
这是因为tag会往下传,不会影响其它的答案。
以上用lazytag实现
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int mod = 998244353; 5 const int maxn = 102000; 6 7 int n,m,cnt; 8 9 int T1[maxn<<3],D1[maxn<<3],lazy1[maxn<<3]; 10 int D2[maxn<<3],M2[maxn<<3],A2[maxn<<3]; 11 int pw2[maxn]; 12 13 void push_down(int now){ 14 T1[now<<1]=1ll*T1[now<<1]*lazy1[now]%mod; 15 T1[now<<1|1]=1ll*T1[now<<1|1]*lazy1[now]%mod; 16 D1[now<<1]=1ll*D1[now<<1]*lazy1[now]%mod; 17 D1[now<<1|1]=1ll*D1[now<<1|1]*lazy1[now]%mod; 18 lazy1[now<<1] = 1ll*lazy1[now<<1]*lazy1[now]%mod; 19 lazy1[now<<1|1] = 1ll*lazy1[now<<1|1]*lazy1[now]%mod; 20 lazy1[now] = 1; 21 } 22 23 void modify1(int now,int tl,int tr,int l,int r){ 24 if(tl > r || tr < l){ 25 T1[now]*=2;T1[now]%=mod; //D1[now]*=2;D1[now]%=mod; 26 T1[now] -= D1[now]; T1[now] += mod; T1[now] %= mod; 27 lazy1[now] *= 2; lazy1[now] %= mod; 28 return; 29 } 30 if(tl >= l && tr <= r){ 31 T1[now] = ((2ll*T1[now]%mod-D1[now]+mod)%mod+pw2[cnt-1])%mod; 32 D1[now] = (D1[now]+pw2[cnt-1])%mod; 33 lazy1[now] = 2ll*lazy1[now]%mod; 34 return; 35 } 36 if(lazy1[now]!=1) push_down(now); 37 int mid = (tl+tr)/2; 38 modify1(now<<1,tl,mid,l,r); modify1(now<<1|1,mid+1,tr,l,r); 39 T1[now] = (1ll*T1[now<<1]+T1[now<<1|1]+D1[now])%mod; 40 } 41 42 void pdm(int now){ 43 D2[now<<1] = 1ll*M2[now]*D2[now<<1]%mod; 44 D2[now<<1|1] = 1ll*M2[now]*D2[now<<1|1]%mod; 45 M2[now<<1] = 1ll*M2[now<<1]*M2[now]%mod; 46 M2[now<<1|1] = 1ll*M2[now<<1|1]*M2[now]%mod; 47 A2[now<<1] = 1ll*A2[now<<1]*M2[now]%mod; 48 A2[now<<1|1] = 1ll*A2[now<<1|1]*M2[now]%mod; 49 M2[now] = 1; 50 } 51 52 void pda(int now){ 53 D2[now<<1] = (D2[now<<1]+A2[now])%mod; 54 D2[now<<1|1] = (D2[now<<1|1]+A2[now])%mod; 55 A2[now<<1] = (A2[now<<1]+A2[now])%mod; 56 A2[now<<1|1] = (A2[now<<1|1]+A2[now])%mod; 57 A2[now] = 0; 58 } 59 60 stack<int> sta; 61 void add1(int now,int dt){ 62 int pp = now; 63 while(pp){sta.push(pp); pp >>= 1;} 64 while(!sta.empty()){ 65 if(lazy1[sta.top()]) push_down(sta.top()); 66 T1[sta.top()] += dt; T1[sta.top()] %= mod; 67 sta.pop(); 68 } 69 D1[now] += dt; D1[now] %= mod; 70 } 71 72 void modify2(int now,int tl,int tr,int l,int r){ 73 if(tl > r || tr < l){ 74 add1(now,D2[now]);D2[now] *=2; D2[now] %= mod; 75 M2[now] = M2[now]*2%mod; A2[now] = A2[now]*2%mod; 76 return; 77 } 78 if(tl >= l && tr <= r){ 79 D2[now] += pw2[cnt-1]; D2[now] %= mod; 80 A2[now]+=pw2[cnt-1];A2[now]%=mod;return; 81 } 82 if(M2[now] != 1) pdm(now); 83 if(A2[now]) pda(now); 84 int mid = (tl+tr)/2; 85 modify2(now<<1,tl,mid,l,r); 86 modify2(now<<1|1,mid+1,tr,l,r); 87 } 88 89 int main(){ 90 scanf("%d%d",&n,&m); 91 for(int i=1;i<=4*n;i++) lazy1[i] = 1,M2[i] = 1; 92 pw2[0] = 1; 93 for(int i=1;i<=m;i++) pw2[i] = 2*pw2[i-1]%mod; 94 for(int i=1;i<=m;i++){ 95 int cas; scanf("%d",&cas); 96 if(cas == 2){printf("%d\n",T1[1]);} 97 else{ 98 int l,r; scanf("%d%d",&l,&r); 99 cnt++; 100 modify1(1,1,n,l,r); 101 modify2(1,1,n,l,r); 102 } 103 } 104 }
以上是关于Luogu5280 [ZJOI2019] 线段树 线段树的主要内容,如果未能解决你的问题,请参考以下文章