zoukankan      html  css  js  c++  java
  • [UER #1] DZY Loves Graph

    题目描述

    开始有 (n) 个点,现在对这 (n) 个点进行了 (m) 次操作,对于第 (i) 个操作(从 (1) 开始编号)有可能的三种情况:

    1. (Add) a b: 表示在 (a) 与$ b$ 之间连了一条长度为 (i) 的边(注意, i是操作编号)。保证 (1≤a,b≤n)

    2. (Delete) k: 表示删除了当前图中边权最大的(k)条边。保证 k 一定不会比当前图中边的条数多。

    3. (Return): 表示撤销第 (i−1) 次操作。保证第 (1) 次操作不是 (Return) 且第 (i−1)次不是 (Return) 操作。

    请你在每次操作后告诉(DZY)当前图的最小生成树边权和。如果最小生成树不存在则输出 (0)

    Input

    第一行两个正整数 (n,m)。表示有 (n) 个点 (m) 个操作。

    接下来 (m) 行每行描述一个操作。

    测试点编号 (n) (m) 其他
    1 (n≤10^3) (m≤10^3) 只有(Add)操作
    2 (n≤10^3) (m≤10^3)
    3 (n≤10^3) (m≤10^3)
    4 (n≤2×10^5) (m≤2×10^5) 只有(Add)操作
    5 (n≤3×10^5) (m≤5×10^5) 只有(Add)操作
    6 (n≤2×10^5) (m≤2×10^5) 没有(Return)操作
    7 (n≤3×10^5) (m≤5×10^5) 没有(Return)操作
    8 (n≤2×10^5) (m≤2×10^5)
    9 (n≤2×10^5) (m≤2×10^5)
    10 (n≤3×10^5) (m≤5×10^5)

    Output

    对于每一个操作输出一行一个整数表示当前最小生成树边权和。

    Sample Input

    2 2
    Add 1 2
    Return
    
    
    5 10
    Add 2 1
    Add 3 2
    Add 4 2
    Add 5 2
    Add 2 3
    Return
    Delete 1
    Add 2 3
    Add 5 2
    Return
    

    Sample Output

    1
    0
    
    
    0
    0
    0
    10
    10
    10
    0
    0
    15
    0
    

    算法一:

    (1-3)号测试点可以直接每次暴力求最小生成树,时间复杂度(O(m*n^2α(n)))得分(30)


    算法二:

    其次,(4-5)号测试点只有(Add)操作的测试点可以发现,由于边权是依次递增的

    由此,一旦构成最小生成树后,便不会发生改变,直接每次加边按照并查集的方法做。

    时间复杂度(O(nα(n))),结合算法一,得分(50)


    算法三:

    我们发现,删边的操作和加边的操作主要是在维护几个连通块

    那么,如何做到可撤回的并查集呢?

    可持久化并查集,当然是按秩合并的并查集了!!

    于是,关于加边和删边的操作我们都解决了。。。

    问题主要在(return)操作上。

    题目中说到,一个(return)的操作的前一个操作不可能是(return)

    也就是说,若第(i)次操作为(return)操作,那么,第(i)次操作的答案和第(i-2)操作答案相同,同时,第(i-1)次操作未执行

    所以,对于一个(Add)或者(Delete)操作,我们只用关心下一次操作是不是(return)就行了。

    于是,我们先进行离线操作。

    对于当前操作为(Add)(Delete)则看下一次操作,若不为(return)直接执行。

    否则,执行完操作后存下答案,然后进行撤回操作。

    时间复杂度(O(n*log_n)),得分(100)


    代码如下

    #include <bits/stdc++.h>
     
    using namespace std;
     
    #define int long long
    #define u64 unsigned long long
    #define u32 unsigned int
    #define reg register
    #define Raed Read
    #define debug(x) cerr<<#x<<" = "<<x<<endl;
    #define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
    #define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
    #define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
    #define erep(i,x) for(reg int i=Head[x]; i; i=Nxt[i])
     
    inline int Read() {
        int res = 0, f = 1;
        char c;
        while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
        do res = (res << 3) + (res << 1) + (c ^ 48);
        while (c = getchar(), c >= 48 && c <= 57);
        return f ? res : -res;
    }
     
    template<class T>inline bool Min(T &a, T const&b) {
        return a > b ? a = b, 1 : 0;
    }
    template<class T>inline bool Max(T &a, T const&b) {
        return a < b ? a = b, 1 : 0;
    }
     
    const int N=5e5+5;
     
    bool MOP1;
     
    int n,m;
     
    struct node {
        int op,a,b;
    } Q[N];
     
    struct T3Add {
        int Fa[N];
        int find(int x) {
            return Fa[x]==x?Fa[x]:Fa[x]=find(Fa[x]);
        }
        inline void solve(void) {
            rep(i,1,n)Fa[i]=i;
            int tot=0,Ans=0;
            rep(i,1,m) {
                if(tot==n-1) {
                    printf("%lld
    ",Ans);
                    continue;
                }
                int a=find(Q[i].a),b=find(Q[i].b);
                if(a!=b) {
                    tot++,Ans+=i;
                    Fa[a]=b;
                }
                if(tot<n-1)puts("0");
                else printf("%lld
    ",Ans);
            }
        }
    } PAdd;
     
    struct T330 {
        struct edge {
            int a,b,c;
        } Edge[N];
        int Fa[N];
        int find(int x) {
            return Fa[x]==x?Fa[x]:Fa[x]=find(Fa[x]);
        }
        inline void solve(void) {
            int tot=0,top=0;
            rep(i,1,m) {
                int op=Q[i].op;
                if(op==1)Edge[++top]=(edge)<%Q[i].a,Q[i].b,i%>;
                if(op==2)top-=Q[i].a;
                if(op==3) {
                    if(Q[i-1].op==1)top--;
                    else top+=Q[i-1].a;
                }
                int Ans=0,res=0;
                rep(j,1,n)Fa[j]=j;
                rep(j,1,top) {
                    int a=find(Edge[j].a),b=find(Edge[j].b);
                    if(a==b)continue;
                    res++,Ans+=Edge[j].c,Fa[a]=b;
                }
                if(res!=n-1)Ans=0;
                printf("%lld
    ",Ans);
            }
        }
    } P30;
     
    struct T3Ac {
        int Fa[N],dep[N],Ans[N];
        struct edge {
            int a,b;
        } Edge[N];
        int find(int x) {
            return Fa[x]==x?Fa[x]:find(Fa[x]);
        }
        int stack[N];
        inline void solve(void) {
            int cnt=0,tot=0,top=0;
            rep(i,1,n)Fa[i]=i;
            rep(i,1,m) {
                int op=Q[i].op;
                if(op==1) {
                    int a=find(Q[i].a),b=find(Q[i].b);
                    if(a!=b)cnt++,tot+=i;
                    if(cnt==n-1)Ans[i]=tot;
                    else Ans[i]=Ans[i-1];
                    if(Q[i+1].op==3) {
                        Ans[i+1]=Ans[i-1];
                        if(a!=b)cnt--,tot-=i;
                    } else {
                        stack[++top]=i;
                        if(a!=b) {
                            if(dep[a]>dep[b])swap(a,b);
                            Fa[a]=b,Max(dep[b],dep[a]+1);
                            Edge[i].a=a,Edge[i].b=b;
                        }
                    }
                }
                if(op==2) {
                    Ans[i]=Ans[stack[top-Q[i].a]];
                    if(Q[i+1].op==3)Ans[i+1]=Ans[i-1];
                    else {
                        int k=Q[i].a;
                        rep(j,1,k) {
                            int Id=stack[top--],A=Edge[Id].a;
                            if(!A)continue;
                            Fa[A]=A;
                            cnt--,tot-=Id;
                        }
                    }
                }
                printf("%lld
    ",Ans[i]);
            }
        }
    } P100;
     
    char S[15];
     
    bool MOP2;
     
    inline void _main(void) {
        n=Raed(),m=Read();
        int f=0;
        rep(i,1,m) {
            scanf("%s",S);
            if(S[0]!='A')f=1;
            if(S[0]=='A')Q[i]=(node)<%1,Read(),Read()%>;
            if(S[0]=='D')Q[i]=(node)<%2,Read(),0%>;
            if(S[0]=='R')Q[i]=(node)<%3,0,0%>;
        }
        if(!f)PAdd.solve();
        else if(n<=1000&&m<=1000)P30.solve();
        else P100.solve();
    }
     
    signed main() {
    #define offline1
    #ifdef offline
        freopen("graph.in", "r", stdin);
        freopen("graph.out", "w", stdout);
        _main();
        fclose(stdin);
        fclose(stdout);
    #else
        _main();
    #endif
        return 0;
    }
    
  • 相关阅读:
    HTML 5 音频
    HTML 5 视频
    HTMl链接- target/ name
    HTML 链接
    OGNL_一点
    struts_表单得到数据
    MySql_十六进制值
    HTML 事件属性(下)
    作业3-2 输入一个正整数 n,再输入 n 个学生的成绩,计算平均成绩,并统计所有及格学生的人数
    作业3-1 .输入一个整数 x,计算并输出下列分段函数 sign(x) 的值
  • 原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11323273.html
Copyright © 2011-2022 走看看