21.6.1 t2
阿新 • • 發佈:2021-06-25
tag:分塊,二分
對操作序列分塊。
對於一個塊,先 \(O(n)\) 處理出當前每個點的真實值。由於一個塊內最多隻有 \(O(B)\) 個點會發生變化,所以可以按照指標關係將 \(O(n)\) 個點縮成 \(O(B)\) 個點,之後的操作就 \(O(B^2)\) 暴力操作。
對於一個詢問,首先在預處理的時候可以處理出每個聯通塊有哪些點,然後排序,詢問時列舉每個聯通塊,二分出這個聯通塊
複雜度 \(O(\frac nB(n+B^2+B^2logn))\)
\(B=300\) 能過
#include<bits/stdc++.h> using namespace std; template<typename T> inline void Read(T &n){ char ch; bool flag=false; while(!isdigit(ch=getchar()))if(ch=='-')flag=true; for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48)); if(flag)n=-n; } typedef long long ll; enum{ MAXN = 100005, B = 300 }; int n, m; struct upd{char opt; int x, y;}q[MAXN]; ll ans[MAXN]; int a[MAXN], to[MAXN], bel[MAXN], ori[MAXN]; ll S[MAXN]; vector<int>vec[MAXN]; char mk[MAXN], vis[MAXN]; int getval(int x){if(vis[x] or !to[x]) return a[x]; vis[x] = true; return a[x]=getval(to[x]);} inline void solve(int l, int r){ static int p[B+5], cont[B+5][MAXN], num[B+5]; int top=0; // printf("solve(%d %d)\n",l,r); memset(vis,false,sizeof vis); memset(mk,false,sizeof mk); for(register int i=l; i<=r; i++) if(q[i].opt=='L' or q[i].opt=='C') if(!mk[q[i].x]) mk[q[i].x] = true, p[++top] = q[i].x; for(register int i=1; i<=n; i++) vec[i].clear(), bel[i] = i; for(register int i=1; i<=n; i++) if(to[i]) vec[to[i]].push_back(i); for(register int i=1; i<=n; i++) ori[i] = getval(i), S[i] = S[i-1]+a[i]; for(register int i=1; i<=top; i++){ int x, y; cont[i][x=y=1] = p[i]; while(x<=y){ int cur = cont[i][x++]; for(register int j:vec[cur]) if(!mk[j]) cont[i][++y] = j, bel[j] = p[i]; } sort(cont[i]+1,cont[i]+y+1); num[i] = y; // printf("%d: ",p[i]); // for(register int j=1; j<=y; j++) printf("%d ",cont[i][j]);puts(""); } for(register int i=1; i<=top; i++) to[p[i]] = bel[to[p[i]]]; for(register int i=l; i<=r; i++){ int x = q[i].x, y = q[i].y; if(q[i].opt=='L' and q[i].y) to[x] = bel[y]; if(q[i].opt=='C') a[x] = y, to[x] = 0; if(q[i].opt=='Q'){ ans[i] = S[y]-S[x-1]; // for(register int j=1; j<=n; j++) vis[j] = false; for(register int j=1; j<=top; j++) vis[p[j]] = false; for(register int j=1; j<=top; j++){ if(y<cont[j][1] or cont[j][num[j]]<x) continue; int dlt = getval(p[j])-ori[p[j]]; int li = lower_bound(cont[j]+1,cont[j]+num[j]+1,x)-cont[j]; int ri = upper_bound(cont[j]+1,cont[j]+num[j]+1,y)-cont[j]-1; assert(x<=cont[j][li] and (li==1 or cont[j][li-1]<x)); assert(cont[j][ri]<=y and (ri==num[j] or y<cont[j][ri+1])); ans[i] += 1ll*dlt*(ri-li+1); // for(register int k=1; k<=num[j]; k++) // if(x<=cont[j][k] and cont[j][k]<=y) ans[i] += dlt; } } } for(register int i=l; i<=r; i++) if(q[i].opt=='L' and q[i].y) to[q[i].x] = q[i].y; else if(q[i].opt=='C') a[q[i].x] = q[i].y, to[q[i].x] = 0; } inline char gc(){char temp;do temp=getchar();while(temp!='L' and temp!='Q' and temp!='C');return temp;} int main(){ // freopen("21.in","r",stdin); // freopen("22.out","w",stdout); Read(n); Read(m); for(register int i=1; i<=n; i++) Read(a[i]); for(register int i=1; i<=m; i++) q[i].opt=gc(), Read(q[i].x), Read(q[i].y);//, assert(q[i].opt!='L' or q[i].y!=0); for(register int i=1; i<=m; i+=B) solve(i,min(m,i+B-1)); for(register int i=1; i<=m; i++) if(q[i].opt=='Q') cout<<ans[i]<<'\n'; return 0; }