题目链接  Envy

题意  给出一个连通的无向图和若干询问。每个询问为一个边集。求是否存在某一棵原图的最小生成树包含了这个边集。

考虑$kruskal$的整个过程,

当前面$k$条边已经完成操作的时候(就是前$k$小的边已经进行并查集缩点,此时部分点已经形成了若干个连通块)

这个时候突然冒出来一些权值相同并且这个权值大于前$k$条边最大权值的边,问这些边是否能同时被某一棵最小生成树包含。

那我们依次检查这突然冒出来的几条边,在原来的这个并查集的基础上,继续进行缩点操作。

如果这些边在处理的时候没有遇到某条边的两个点在连边之前已经连通的情况,那么这些边能同时被某一棵最小生成树包含。

反之亦然。

对于这道题我们要做的就是把所有询问离线,把每条询问边塞到对应的权值里面。

当我现在要检查权值为$x$的某些同一个询问里的边的时候,首先要保证那些权值小于$x$的边都已经进行了并查集缩点。

然后把这些权值为$x$的某些同一个询问里的边想象成刚刚说的“突然冒出来的几条边”,检查就可以了。

如果不行的话这个询问的$id$的答案就是$NO$了。

因为同一个权值里面可能会有(其实是一般都有)询问id不同的边,那么处理完某一批边之后我们要对询问的时候改动的并查集撤销。

开个栈记录一下即可。

#include <bits/stdc++.h>

using namespace std;

#define	rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second typedef pair <int, int> PII; const int N = 5e5 + 10; struct node{
int x, y, z;
void scan(){ scanf("%d%d%d", &x, &y, &z);}
} e[N]; struct query{
int x, y, id;
friend bool operator < (const query &a, const query &b){
return a.id < b.id;
}
}; int father[N], ret[N], n, m, qu, now, opnum;
stack <PII> s;
vector <query> v[N];
vector <PII> g[N]; int getfather(int x){
if (father[x]){
s.push(MP(x, father[x]));
father[x] = getfather(father[x]);
return father[x];
} else return x;
} int gf(int x){ return father[x] ? father[x] = gf(father[x]) : x;} void work(int x, int y){
int fx = gf(x), fy = gf(y);
if (fx ^ fy) father[fx] = fy;
} void solve(int cnt, int x, int y){
while (!s.empty()) s.pop();
rep(i, x, y){
int fx = getfather(v[cnt][i].x), fy = getfather(v[cnt][i].y);
if (fx == fy) ret[v[cnt][i].id] = 1;
else{
s.push(MP(fx, father[fx]));
father[fx] = fy;
}
} while (!s.empty()){
father[s.top().fi] = s.top().se;
s.pop();
}
} int main(){ scanf("%d%d", &n, &m);
rep(i, 1, m){
e[i].scan();
g[e[i].z].push_back(MP(e[i].x, e[i].y));
} scanf("%d", &qu);
rep(i, 1, qu){
int opnum;
scanf("%d", &opnum);
rep(j, 1, opnum){
int x;
scanf("%d", &x);
v[e[x].z].push_back({e[x].x, e[x].y, i});
}
} rep(i, 1, 5e5) sort(v[i].begin(), v[i].end());
rep(i, 1, 5e5){
for (auto u : g[i - 1]) work(u.fi, u.se);
int sz = v[i].size();
if (sz == 0) continue;
int now = 0;
while (now < sz){
int j = now;
while (j + 1 < sz && v[i][j + 1].id == v[i][j].id) ++j;
solve(i, now, j);
now = j + 1;
}
} rep(i, 1, qu) puts(ret[i] ? "NO" : "YES");
return 0;
}

Codeforces 891C Envy(MST + 并查集的撤销)的更多相关文章

  1. Codeforces Gym 100463E Spies 并查集

    Spies Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100463/attachments Desc ...

  2. Codeforces 859E Desk Disorder 并查集找环,乘法原理

    题目链接:http://codeforces.com/contest/859/problem/E 题意:有N个人.2N个座位.现在告诉你这N个人它们现在的座位.以及它们想去的座位.每个人可以去它们想去 ...

  3. Codeforces - 828C String Reconstruction —— 并查集find()函数

    题目链接:http://codeforces.com/contest/828/problem/C C. String Reconstruction time limit per test 2 seco ...

  4. Codeforces 571D - Campus(并查集+线段树+DFS 序,hot tea)

    Codeforces 题目传送门 & 洛谷题目传送门 看到集合的合并,可以本能地想到并查集. 不过这题的操作与传统意义上的并查集不太一样,传统意义上的并查集一般是用来判断连通性的,而此题还需支 ...

  5. CodeForces 455C Civilization (并查集+树的直径)

    Civilization 题目链接: http://acm.hust.edu.cn/vjudge/contest/121334#problem/B Description Andrew plays a ...

  6. Codeforces 650C Table Compression (并查集)

    题意:M×N的矩阵 让你保持每行每列的大小对应关系不变,将矩阵重写,重写后的最大值最小. 思路:离散化思想+并查集,详见代码 好题! #include <iostream> #includ ...

  7. Codeforces 468B Two Sets 并查集

    题目大意:给出n个数,要求将n个数分配到两个集合中,集合0中的元素x,要求A-x也再0中,同理1集合. 写了几个版本号,一直WA在第8组数据...最后參考下ans,写了并查集过了 学到:1.注意离散的 ...

  8. CodeForces - 893C Rumor【并查集】

    <题目链接> 题目大意: 有n个人,其中有m对朋友,现在你有一个秘密你想告诉所有人,第i个人愿意出价a[i]买你的秘密,获得秘密的人会免费告诉它的所有朋友(他朋友的朋友也会免费知道),现在 ...

  9. CodeForces 566D Restructuring Company (并查集+链表)

    题意:给定 3 种操作, 第一种 1 u v 把 u 和 v 合并 第二种 2 l r 把 l - r 这一段区间合并 第三种 3 u v 判断 u 和 v 是不是在同一集合中. 析:很容易知道是用并 ...

随机推荐

  1. 2940: [Poi2000]条纹(Multi_SG)

    2940: [Poi2000]条纹 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 114  Solved: 72[Submit][Status][Dis ...

  2. Redis实现之事件

    事件 Redis服务器是一个事件驱动程序,服务器需要处理以下两类事情: 文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对 ...

  3. laravel5.2总结--集合

          类(Laravel集合基类) Illuminate\Support\Collection 类提供一个流畅.便利的封装来操控数组数据,官方提供了很多辅助函数,方便对数据进行各种处理,Coll ...

  4. 查看2个Python字典的相同以及不同之处

    a = { "x":1, "y":2, "z":3 } b = { "x":1, "w":11, & ...

  5. Python-S9-Day115——Flask Web框架基础

    01 今日内容概要 02 内容回顾 03 Flask框架:配置文件导入原理 04 Flask框架:配置文件使用 05 Flask框架:路由系统 06 Flask框架:请求和响应相关 07 示例:学生管 ...

  6. backpropagation算法示例

    backpropagation算法示例 下面举个例子,假设在某个mini-batch的有样本X和标签Y,其中\(X\in R^{m\times 2}, Y\in R^{m\times 1}\),现在有 ...

  7. 菜鸟之路——机器学习之HierarchicalClustering层次分析及个人理解

    这个算法.我个人感觉有点鸡肋.最终的表达也不是特别清楚. 原理很简单,从所有的样本中选取Euclidean distance最近的两个样本,归为一类,取其平均值组成一个新样本,总样本数少1:不断的重复 ...

  8. [oldboy-django][2深入django]班级管理(Form)--编辑

    1.需求:编辑班级,难点:点击编辑按钮后,页面如何显示 待编辑 班级的信息(用Form实现), 以及Url 设置 2 url url(r'^edit_class/nid=(?P<nid>\ ...

  9. LAMP第四部分 mysql相关

    1. 忘记root密码http://www.lishiming.net/thread-252-1-1.html 进入mysqlwhich mysql/usr/local/mysql/bin/mysql ...

  10. BZOJ 3437:小P的牧场(DP+斜率优化)

    小P的牧场[题目描述]背景:小P 是个特么喜欢玩MC 的孩纸...小P 在MC 里有n 个牧场,自西向东呈一字形排列(自西向东用1…n 编号),于是他就烦恼了:为了控制这n 个牧场,他需要在某些牧场上 ...