题目:

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

  • Add a b: 表示在 \(a\) 与 \(b\) 之间连了一条长度为 \(i\) 的边(注意,\(i\)是操作编号)。保证 \(1 \leq a, b \leq n\)。
  • Delete k: 表示删除了当前图中边权最大的k条边。保证 \(k\) 一定不会比当前图中边的条数多。
  • Return: 表示撤销第 \(i-1\) 次操作。保证第 \(1\) 次操作不是 Return 且第 \(i-1\) 次不是 Return 操作。

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

题解:

首先我们来挖掘一下题目的性质.

  1. 加入的边权值递增
  2. 如果一条边被删除,那么所有大于这条边权值的边要么没被加入,要么已经被删除.

    所以我们可以直接大力可持久化并查集.

    \(O(mlog^2n)\) 做一些有理有据的底层优化应该能过掉.

但其实这道题没有那么复杂.

首先我们先忽略掉Return操作.

我们考虑维护动态加入和删除的并查集.

我们可以直接在\(O(mlogn)\)内完成.

但其实加上Return操作后对我们的做法也没有什么影响.

进行每一次操作的时候,我们首先检查一下下一操作是不是Return操作

如果不是Return我们就直接在现有的状态上进行修改.

如果是Return那么我们就计算出当前操作的影响,并不把这份影响加入到我们当前的状态中.

这样我们就可以直接用一维数组解决掉啦..

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch > '!');if(flag) x=-x;
}
const int maxn = 510010;
int fa[maxn],siz[maxn];
inline int find(int x){
while(fa[x] != x) x = fa[x];
return x;
}
int ope[maxn];
char s[12];
struct ope{
int op,u,v;
}op[maxn];
ll ans[maxn],sum[maxn];
int main(){
int n,m;read(n);read(m);
for(int i=1;i<=n;++i) fa[i] = i,siz[i] = 1;
for(int i=1;i<=m;++i){
scanf("%s",s);
if(*s == 'A'){
op[i].op = 1;
read(op[i].u);
read(op[i].v);
}else if(*s == 'D'){
op[i].op = 2;
read(op[i].u);
}else if(*s == 'R') op[i].op = 3;
}
int ecnt = 0,nodecnt = n;
for(int i=1;i<=m;++i){
if(op[i].op == 1){
if(op[i+1].op == 3){
if(nodecnt == 1) printf("%lld\n",ans[ecnt]);
else if(nodecnt == 2){
int x = find(op[i].u);
int y = find(op[i].v);
if(x == y) puts("0");
else printf("%lld\n",sum[ecnt] + i);
}else puts("0");
printf("%lld\n",ans[ecnt]);
++ i;
}else{
ans[ecnt+1] = ans[ecnt];
sum[ecnt+1] = sum[ecnt];
++ecnt;
int x = find(op[i].u);
int y = find(op[i].v);
if(x == y){
printf("%lld\n",ans[ecnt]);
ope[ecnt] = 0;
continue;
}
if(siz[x] > siz[y]) swap(x,y);
fa[x] = y;siz[y] += siz[x];ope[ecnt] = x;
sum[ecnt] += i;
if(--nodecnt == 1) ans[ecnt] = sum[ecnt];
printf("%lld\n",ans[ecnt]);
}
}else if(op[i].op == 2){
if(op[i+1].op == 3){
printf("%lld\n",ans[ecnt-op[i].u]);
++ i;
printf("%lld\n",ans[ecnt]);
}else{
for(int j=0;j<op[i].u;++j){
if(ope[ecnt] != 0){
int x = ope[ecnt];
++ nodecnt;
siz[fa[x]] -= siz[x];
fa[x] = x;
}-- ecnt;
}
printf("%lld\n",ans[ecnt]);
}
}
}
return 0;
}

uoj problem 14 DZY Loves Graph的更多相关文章

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

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

  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】【UER #1】DZY Loves Graph

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

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

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

  5. Codeforces Round #FF (Div. 2):Problem A - DZY Loves Hash

    A. DZY Loves Hash time limit per test 1 second memory limit per test 256 megabytes input standard in ...

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

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

  7. UOJ14 DZY Loves Graph

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

  8. [UER #1] DZY Loves Graph

    题目描述 开始有 \(n\) 个点,现在对这 \(n\) 个点进行了 \(m\) 次操作,对于第 \(i\) 个操作(从 \(1\) 开始编号)有可能的三种情况: \(Add\) a b: 表示在 \ ...

  9. 【UER #1】DZY Loves Graph

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

随机推荐

  1. Entity Framework(1)——Connections and Models

    原文:https://msdn.microsoft.com/en-us/data/jj592674 应该选择CodeFirst.ModelFirst还是databaseFirst网上已经很多资料了,这 ...

  2. Java 学习 day08

    01-面向对象(多态-概念) package myFirstCode; /* 多态:可以理解为事务存在的多种体现形态. 人:男人,女人 动物:猫,狗 猫 x = new 猫(); 动物 x = new ...

  3. UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-3: ordinal not in range(256)

    今天使用MySQLdb往MySQL插入中文数据遇到一个异常: UnicodeEncodeError: 'latin-1' codec can't encode characters in positi ...

  4. Numerical Differentiation 数值微分

    zh.wikipedia.org/wiki/數值微分 数值微分是数值方法中的名词,是用函数的值及其他已知资讯来估计一函数导数的算法. http://mathworld.wolfram.com/Nume ...

  5. Swift 枚举简单使用

    //定义一个枚举 Direction 枚举字符名字 enum Direction{ case North case South case East case West }; enum Directio ...

  6. c的详细学习(7)指针学习(一)

    指针是c语言的一个重要概念,指针类型是c语言最有特色的数据类型: *利用指针编写的程序可使调用函数共享变量或数据结构,实现双向数据通信: *可以实现内存空间的动态存储分配:可以提高程序的编译效率和执行 ...

  7. 练习题目 :if for while else range、xrange、zip

    range在内存中直接生成指定的序列,当序列非常大时会浪费内存资源: xrange则不会直接生成一个list,而是每次调用返回其中的一个值,而非直接全部生成存于内存中 range([start,] s ...

  8. linux常用端口

    linux常用端口:已有的比较好的博客! 本人常用端口备份: 50070 hdfs hdfs集群监控端口 8088 yarn yarn集群监控端口 8983 solr solr服务查询端口60010 ...

  9. 使用 sqoop 将mysql数据导入到hdfs(import)

    Sqoop 将mysql 数据导入到hdfs(import) 1.创建mysql表 CREATE TABLE `sqoop_test` ( `id` ) DEFAULT NULL, `name` va ...

  10. 测试CPU核心个数

    //测试CPU核心个数 #if !defined (_WIN32) && !defined (_WIN64) #define LINUX #include <unistd.h&g ...