21.6.1 t2
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;
}