题目:

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;
}

最新文章

  1. python爬虫学习(9) —— 一些工具和语法
  2. knockoutJS学习笔记02:jsRender模板引擎
  3. Node.js入门:Hello World
  4. mysql的一些基本操作语句
  5. nodejs 文件上传
  6. Using self-defined Parcelable objects during an Android AIDL RPC / IPC call
  7. string.Join和Reverse的简单使用示例
  8. 查看ORACLE事务隔离级别方法(转)
  9. iis配置网址(主机名)
  10. three.js提供的几何体
  11. Linux笔记③(ftp、nfs、ssh服务器搭建)
  12. codeforces 630C - Lucky Numbers 递推思路
  13. PHP方法实现1-9数列中添加‘+’,‘-’或&#39;&#39;,使和为100,并输出数列
  14. iot会议纪要 20180105
  15. Hibernate框架_搭建第一个Hibernate框架
  16. 数据结构(java版)学习笔记(一)——线性表
  17. 【案例分享】crontab执行脚本异常问题
  18. DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件
  19. vim 加密(crypt)文本文档
  20. 《spark快速大数据分析》

热门文章

  1. fzu2020( c(n,m)%p,其中n, m, p (1 &lt;= m &lt;= n &lt;= 10^9, m &lt;= 10^4, m &lt; p &lt; 10^9, p是素数) )
  2. jquery获取页面iframe内容
  3. 【BZOJ3302】[Shoi2005]树的双中心 DFS
  4. Storm编程模型及Worker通信机制
  5. 小米4s经常断网
  6. Mac标识物理位置算法 import Levenshtein mac列表特征值
  7. html5plus (H5 WebApp)
  8. PAT 1065. 单身狗(25)
  9. FPGA低温不能启动分析
  10. python发布包流程