题目描述

开始有 \(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;
}

[UER #1] DZY Loves Graph的更多相关文章

  1. UOJ14 UER #1 DZY Loves Graph(最小生成树+并查集)

    显然可以用可持久化并查集实现.考虑更简单的做法.如果没有撤销操作,用带撤销并查集暴力模拟即可,复杂度显然可以均摊.加上撤销操作,删除操作的复杂度不再能均摊,但注意到我们在删除时就可以知道他会不会被撤销 ...

  2. 【UER #1】[UOJ#12]猜数 [UOJ#13]跳蚤OS [UOJ#14]DZY Loves Graph

    [UOJ#12][UER #1]猜数 试题描述 这一天,小Y.小D.小C正在愉快地玩耍. 小Y是个数学家,他一拍脑袋冒出了一个神奇的完全平方数 n. 小D是个机灵鬼,很快从小Y嘴里套出了 n的值.然后 ...

  3. 学长小清新题表之UOJ 14.DZY Loves Graph

    学长小清新题表之UOJ 14.DZY Loves Graph 题目描述 \(DZY\)开始有 \(n\) 个点,现在他对这 \(n\) 个点进行了 \(m\) 次操作,对于第 \(i\) 个操作(从 ...

  4. 【UER #1】DZY Loves Graph

    UOJ小清新题表 题目内容 UOJ链接 DZY开始有\(n\)个点,现在他对这\(n\)个点进行了\(m\)次操作,对于第\(i\)个操作(从\(1\)开始编号)有可能的三种情况: Add a b: ...

  5. 【UOJ #14】【UER #1】DZY Loves Graph

    http://uoj.ac/problem/14 题解很好的~ 不带路径压缩的并查集能保留树的原本形态. 按秩合并并查集可以不用路径压缩,但是因为此题要删除,如果把深度当为秩的话不好更新秩的值,所以把 ...

  6. 【UER #1】DZY Loves Graph(待卡常数)

    题解: 正解是可持久化并查集 但这个显然是lct可以维护的 但这常数是个问题啊??? #include <bits/stdc++.h> using namespace std; struc ...

  7. uoj #14.【UER #1】DZY Loves Graph

    http://uoj.ac/problem/14 由于加入的边权递增,可以直接运行kruskal并支持撤销,但这样如果反复批量删边和撤销,时间复杂度会退化,因此需要对删边操作加上延时处理,只有在删边后 ...

  8. 2019.01.22 uoj#14. 【UER #1】DZY Loves Graph(并查集)

    传送门 题意简述: 要求支持以下操作: 在a与b之间连一条长度为i的边(i是操作编号):删除当前图中边权最大的k条边:表示撤销第 i−1次操作,保证第1次,第i−1 次不是撤回操作. 要求在每次操作后 ...

  9. UOJ14 DZY Loves Graph

    DZY开始有 nn 个点,现在他对这 nn 个点进行了 mm 次操作,对于第 ii 个操作(从 11 开始编号)有可能的三种情况: Add a b: 表示在 aa 与 bb 之间连了一条长度为 ii ...

随机推荐

  1. head first 设计模式笔记9-迭代器模式

    迭代器模式:提供一种方法顺序访问一个集合对象中的各个元素,而又不暴露其内部的表示. 迭代器接口 /** * @author oy * @date 2019年9月22日 上午9:03:08 * @ver ...

  2. jdk,jre下载安装

    JDK安装https://blog.csdn.net/u012934325/article/details/73441617/jre需要手动生成在JDK安装目录下,的bin cmd执行bin\ jli ...

  3. web前端:上传文件夹(需支持多浏览器)

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 先说下要求: PC端全平台支持,要求支持Windows,Mac,Linux 支持所 ...

  4. 暑假集训#2 div1 J 四点直角 J - Space Invader 四点共面+跨立实验

    题意:给你四个点,判断能否先依次通过A,B两点,然后再在某个地方只进行一次直角转弯再一次经过C,D两点: #include <iostream> #include <cstdio&g ...

  5. jQuery_attr()操作

    下面来介绍jQuery的属性attr()操作: <!DOCTYPE html> <html> <head> <meta charset="UTF-8 ...

  6. BZOJ 2655 calc (组合计数、DP、多项式、拉格朗日插值)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2655 题解 据说有一种神仙容斥做法,但我不会. 以及貌似网上大多数人的dp和我的做法都不 ...

  7. 使用Hive-JDBC遇到的一些问题解决

    使用Hive-JDBC遇到的一些问题解决(转) 标签(空格分隔): Hive 1,java.lang.NoClassDefFoundError: org/apache/hive/service/cli ...

  8. IDM非补丁破解方法

    参考 http://tieba.baidu.com/p/3878377959 备份文章 在网络和共享中心中打开防火墙 高级设置->出站规则->新建规则 打开新建规则向导. 程序-> ...

  9. 使用ElementUI创建项目

    从 0 开始搭建 element 项目 第一步,安装 Nodejs/NPM https://nodejs.org/zh-cn/download/ 下载安装即可! 第二步,安装 vue-cli 打开 c ...

  10. 15个流行的python框架

    Django: Python Web应用开发框架 Django 应该是最出名的Python框架,GAE甚至Erlang都有框架受它影响.Django是走大而全的方向,它最出名的是其全自动化的管理后台: ...