1 条题解

  • 0
    @ 2025-8-24 22:12:40

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Brodal_Queue
    EI 天下第一可爱!

    搬运于2025-08-24 22:12:40,当前版本为作者最后更新于2019-11-04 20:21:12,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    emmm 这里是萌新的第一篇题解


    首先想想没有加边怎么做:

    由于维护的是必经点,也就是割点的信息。
    很容易想到构建圆方树,对于每个点双连通分量建一个方点,点双中的点都连过去,其它边都去掉。

    既然还有动态加边,首先当然是用 Link-Cut Tree\text{Link-Cut Tree} 啦。

    对于 22 操作,就直接把 xx 点 splay 上去,直接修改点权;对于 33 操作,就是路径求和 + 路径权值变 00,也没什么好说的。

    主要说一下 11 操作的做法:

    首先两点不连通,当然是直接连上去;如果已连通,就把路径上的边都断掉,所有点都连向一个方点。
    这样看起来非常暴力,但实际上时间复杂度是对的:用势能分析容易证明,复杂度为 O(qlogn)\text O(q\log n)

    ps:有一个小优化,就是当一条路径上除了两端全是方点时,就直接忽略连边操作,对答案没有影响。

    代码如下:

    #pragma GCC optimize (2)
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define N 1000003
    #define ll long long
    using namespace std;
    
    ll sum[N],a[N];
    int son[N][2],fa[N],size[N],st[N];
    bool tag[N],rev[N],real[N];
    
    inline void pushup(int u){
        size[u] = size[son[u][0]]+size[son[u][1]]+real[u];
        sum[u] = sum[son[u][0]]+sum[son[u][1]]+a[u];
    }
    
    inline bool notrt(int u){
        return son[fa[u]][0]==u||son[fa[u]][1]==u;
    }
    
    inline void push_tag(int u){
        sum[u] = a[u] = 0;
        tag[u] = true;
    }
    
    inline void push_rev(int u){
        swap(son[u][0],son[u][1]);
        rev[u] ^= 1;
    }
    
    inline void pushdown(int u){
        if(tag[u]){
            if(son[u][0]) push_tag(son[u][0]);
            if(son[u][1]) push_tag(son[u][1]);
            tag[u] = 0;
        }
        if(rev[u]){
            if(son[u][0]) push_rev(son[u][0]);
            if(son[u][1]) push_rev(son[u][1]);
            rev[u] = 0;
        }
    }
    
    inline bool check(int u){
    	return son[fa[u]][1]==u;
    }
    
    inline void rotate(int x){
        int y = fa[x],z = fa[y];
        int k = son[y][1]==x,w = son[x][k^1];
        if(notrt(y)) son[z][check(y)] = x;
        son[x][k^1] = y;
        son[y][k] = w;
        if(w) fa[w] = y;
        fa[y] = x,fa[x] = z;
        pushup(y);
    }
    
    inline void splay(int x){
        int y = x,z = 1;
        st[1] = y;
        while(notrt(y)) st[++z] = y = fa[y];
        while(z) pushdown(st[z--]);
        while(notrt(x)){
            y = fa[x],z = fa[y];
            if(notrt(y)) rotate(check(x)==check(y)?y:x);
            rotate(x);
        }
        pushup(x);
    }
    
    inline void access(int u){
        for(int v=0;u;u=fa[v=u])
            splay(u),son[u][1] = v,pushup(u);
    }
    
    inline void makeroot(int u){
        access(u),splay(u);
        push_rev(u);
    }
    
    inline void link(int u,int v){
        makeroot(u);
        fa[u] = v;
    }
    
    inline void split(int u,int v){
        makeroot(u);
        access(v),splay(v);
    }
    
    inline void cut(int u,int v){
        split(u,v);
        son[v][0] = fa[u] = 0;
        pushup(v);
    }
    
    inline ll clear(int u,int v){
        split(u,v);
        ll res = sum[v];
        push_tag(v);
        return res;
    }
    
    int n,q,top,qaq;
    ll ans;
    int fk[N],stk[N];
    
    inline int find(int x){
        while(x!=fk[x]) x = fk[x] = fk[fk[x]];
        return x;
    }
    
    inline void fuckyou(ll &x){
        x ^= ans%n;
    	if(x>n) x %= n;
    	if(!x) x = 1;
    }
    
    void dfs(int u){
        if(!u) return;
        pushdown(u);
        dfs(son[u][0]);
        stk[++top] = u;
        dfs(son[u][1]);
    }
    
    int main(){
        int op;
        ll x,y;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;++i){
            fk[i] = i;
            real[i] = true;
        }
        qaq = n;
        while(q--){
            scanf("%d%lld%lld",&op,&x,&y);
            fuckyou(x),fuckyou(y);
            if(op==1){
                if(find(x)==find(y)){
                    split(x,y);
                    if(size[y]<=2) continue;
                    top = 0;
                    dfs(y);
                    ++qaq;
                    for(int i=1;i<top;++i) cut(stk[i],stk[i+1]);
                    for(int i=1;i<=top;++i) link(stk[i],qaq);
                }else{
                    link(x,y);
                    fk[find(x)] = find(y);
                }
            }else if(op==2){
                splay(x);
                a[x] += y;
            }else{
                ans = find(x)==find(y)?clear(x,y):0ll;
                printf("%lld\n",ans);
            }
        }
    }
    

    因为之前有一道 P5489 所以这题就显得比较模板(

    • 1

    信息

    ID
    4499
    时间
    1500ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者