1 条题解

  • 0
    @ 2025-8-24 23:00:00

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar AN6M
    极其弱智的头像

    搬运于2025-08-24 23:00:00,当前版本为作者最后更新于2025-02-26 20:13:23,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    我的做法不同于清一色的 LCT,只需要用到最小生成树和并查集。

    考虑把每条边赋一个权值 tt 表示加入图的时间,从这张图上扯出一个最小生成树森林。

    考虑依次在树上加边,对于一条要加入的边可以暴力往上加边,对于每一条树边第一次加入的必然是它本身。在第二次加边的时候就形成了环,可以用并查集合并两个节点。由于每条边最多加两次,所以总复杂度可以做到 O(nα(n))O(n\alpha(n))

    这里偷懒写了一个 O(nlogn)O(n\log n) 的写法。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define N 200010
    int n,m,q,tot,fa[N],dep[N],siz[N],trfa[N],s[N],sum[N];
    bool vis[N];
    struct stu{
        int u,v,tim;
        friend bool operator<(stu a,stu b){
            return a.tim<b.tim;
        }
    }e[N<<1],ask[N],g[N];
    vector<int>to[N];
    int find(int x){
        return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    void merge(int x,int y){
        x=find(x);
        y=find(y);
        if(x==y){
            return;
        }
        if(siz[x]<siz[y]){
            swap(x,y);
        }
        fa[y]=x;
        siz[x]+=siz[y];
        sum[x]+=sum[y];
    }
    void mergetofa(int x,int y){
        x=find(x);
        y=find(y);
        if(x==y){
            return;
        }
        fa[y]=x;
        sum[x]+=sum[y];
    }
    void dfs(int x,int fa){
        vis[x]=1;
        trfa[x]=fa;
        dep[x]=dep[fa]+1;
        for(int i=0;i<to[x].size();i++){
            int y=to[x][i];
            if(y==fa){
                continue;
            }
            dfs(y,x);
        }
    }
    void MERGE(int x,int y){
        if(find(x)==find(y)){
            return;
        }
        x=find(x);
        y=find(y);
        while(find(y)!=find(x)){
            if(dep[find(x)]>dep[find(y)]){
                swap(x, y);
            }
            if(!s[y]){
                s[y]++;
            }
            else{
                mergetofa(find(trfa[y]),y);
            }
            y=find(trfa[y]);
        }
    }
    signed main(){
        cin>>n>>m>>q;
        for(int i=1;i<=n;i++){
            fa[i]=i;
            siz[i]=1;
        }
        for(int i=1;i<=m;i++){
            tot++;
            cin>>e[tot].u>>e[tot].v;
            e[tot].tim=0;
            // cout<<e[tot].u<<' '<<e[tot].v<<' '<<e[tot].tim<<'\n';
            g[i]=e[tot];
        }
        for(int i=1;i<=q;i++){
            cin>>ask[i].u>>ask[i].v;
            ask[i].tim=i;
            e[++tot]=ask[i];
            // cout<<e[tot].u<<' '<<e[tot].v<<' '<<e[tot].tim<<'\n';
        }
        int added=0;
        sort(e+1,e+tot+1);
        for(int i=1;i<=tot;i++){
            if(added==n-1){
                break;
            }
            int x=find(e[i].u),y=find(e[i].v);
            if(x==y){
                continue;
            }
            merge(x,y);
            added++;
            to[e[i].u].push_back(e[i].v);
            to[e[i].v].push_back(e[i].u);
            // cout<<e[i].u<<' '<<e[i].v<<' '<<e[i].tim<<'\n';
        }
        for(int i=1;i<=n;i++){
            fa[i]=i;
            siz[i]=1;
            sum[i]=1;
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                dfs(i,0);
            }
        }
        // for(int i=1;i<=n;i++){
        //     cout<<trfa[i]<<' ';
        // }
        // cout<<'\n';
        for(int i=1;i<=m;i++){
            int x=find(g[i].u),y=find(g[i].v);
            MERGE(x,y);
        }
        for(int i=1;i<=q;i++){
            int x=find(ask[i].u),y=find(ask[i].v);
            if(x==y){
                cout<<sum[x]<<'\n';
                continue;
            }
            MERGE(x,y);
            x=find(ask[i].u),y=find(ask[i].v);
            if(x==y){
                cout<<sum[x]<<'\n';
            }
            else{
                cout<<"No\n";
            }
        }
        return 0;
    }
    

    练习:https://www.luogu.com.cn/problem/P6351

    • 1

    信息

    ID
    10451
    时间
    1000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者