1. 程式人生 > 其它 >21.6.1 t2

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