LOJ2251 [ZJOI2017] 树状数组【线段树】【树套树】
题目分析:
对于一个$add$操作,它的特点是与树状数组的查询相同,会给$1$到它自己产生影响,而$query$操作则会途径所有包含它的树状数组点。现在$add$操作具有前向性(不会影响之后的点)。所以实际上这是求后缀和。
现在我们知道,对于$query(l,r)$,它等于${Xor}_{i=l-1}^{r-1}A[i]$。与原答案异或,得到$A[l-1] \oplus A[r]$,若它为$1$则假,否则为真。所以我们把它看作平面上的点,对于一个$add(l,r)$操作,会对右端点在其中的产生$\frac{1}{r-l+1}$的改变影响,对两端都在其中的产生$\frac{2}{r-l+1}$的改变影响,对左端点在其中的产生$\frac{1}{r-l+1}$的改变影响。标记合并不难。然后标记永久化一下就行了。
对于$l=1$的单独处理。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 105000; 5 6 const int mod = 998244353; 7 8 int n,m,num=2,xL,xR,yL,yR,ans; 9 struct qy{ 10 int cas,l,r; 11 }Q[maxn]; 12 13 struct node{ 14 int ch[2],root,data; 15 }T[maxn*300]; 16 17 int fast_pow(int now,int pw){ 18 int res = 1,bit = 1,fun = now; 19 while(bit <= pw){ 20 if(bit & pw) res = (1ll*res*fun)%mod; 21 fun = (1ll*fun*fun)%mod; bit<<=1; 22 } 23 return res; 24 } 25 26 int merge(int p1,int p2){return ((1ll*p1*(1-p2)+1ll*p2*(1-p1))%mod+mod)%mod;} 27 28 void Query(int now,int tl,int tr,int l,int r){ 29 int pls = T[now].root,ll = tl,rr = n; 30 while(true){ 31 int mid = (ll+rr)/2; 32 ans = merge(ans,(1-T[pls].data+mod)%mod); 33 if(mid >= r){ 34 if(!T[pls].ch[0]) break; 35 else pls = T[pls].ch[0]; 36 rr = mid; 37 }else{ 38 if(!T[pls].ch[1]) break; 39 else pls = T[pls].ch[1]; 40 ll = mid+1; 41 } 42 } 43 int mid = (tl+tr)/2; 44 if(mid >= l){if(T[now].ch[0])Query(T[now].ch[0],tl,mid,l,r);} 45 else{if(T[now].ch[1])Query(T[now].ch[1],mid+1,tr,l,r);} 46 } 47 48 void M2(int now,int tl,int tr,int data){ 49 if(tl >= yL && tr <= yR){ 50 T[now].data = merge(T[now].data,data); 51 return; 52 } 53 int mid = (tl+tr)/2; 54 if(!T[now].ch[0] && !T[now].ch[1]){ 55 T[now].ch[0] = ++num; T[now].ch[1] = ++num; 56 T[num-1].data = 1; T[num].data = 1; 57 } 58 if(mid >= yL) M2(T[now].ch[0],tl,mid,data); 59 if(mid < yR) M2(T[now].ch[1],mid+1,tr,data); 60 } 61 62 void Modify(int now,int tl,int tr,int data){ 63 if(tl >= xL && tr <= xR){ 64 M2(T[now].root,tl,n,data); 65 return; 66 } 67 int mid = (tl+tr)/2; 68 if(mid >= xL){ 69 if(T[now].ch[0]==0){ 70 num++;T[now].ch[0] = num; 71 num++;T[num-1].root = num;T[num].data = 1; 72 } 73 Modify(T[now].ch[0],tl,mid,data); 74 } 75 if(mid < xR){ 76 if(T[now].ch[1]==0){ 77 num++;T[now].ch[1] = num; 78 num++;T[num-1].root = num;T[num].data = 1; 79 } 80 Modify(T[now].ch[1],mid+1,tr,data); 81 } 82 } 83 84 void read(){ 85 T[1].root = 2; T[2].data = 1; 86 scanf("%d%d",&n,&m); 87 for(int i=1;i<=m;i++) scanf("%d%d%d",&Q[i].cas,&Q[i].l,&Q[i].r); 88 } 89 90 void work(){ 91 int cnt = 0; 92 for(int i=1;i<=m;i++){ 93 if(Q[i].cas == 1){ 94 cnt^=1; xL = 0,xR = Q[i].l-1,yL = Q[i].l,yR = Q[i].r; 95 Modify(1,0,n,fast_pow(Q[i].r-Q[i].l+1,mod-2)); 96 xL = Q[i].l,xR = Q[i].r,yL = Q[i].l,yR = Q[i].r; 97 Modify(1,0,n,2*fast_pow(Q[i].r-Q[i].l+1,mod-2)%mod); 98 xL = Q[i].l,xR = Q[i].r,yL = Q[i].r+1,yR = n; 99 Modify(1,0,n,fast_pow(Q[i].r-Q[i].l+1,mod-2)); 100 }else{ 101 ans = 1; Query(1,0,n,Q[i].l-1,Q[i].r); 102 if((Q[i].l == 1 && (!cnt))||Q[i].l != 1) printf("%d\n",ans); 103 else printf("%d\n",(1-ans+mod)%mod); 104 } 105 } 106 } 107 108 int main(){ 109 read(); 110 work(); 111 return 0; 112 }