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 }

 

posted @ 2019-05-20 18:14  menhera  阅读(306)  评论(0编辑  收藏  举报