[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\n",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\n",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\n",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\n",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;
}
posted @ 2019-08-08 19:30  dsjkafdsaf  阅读(222)  评论(0编辑  收藏  举报