CF 891C Envy 最小生成树+可撤销并查集
Posted kaka0010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF 891C Envy 最小生成树+可撤销并查集相关的知识,希望对你有一定的参考价值。
文章目录
题意
给定n个定,m条边,接下来有k组询问,每次给定一个集合,问能否用这些集合的点构成MST。
分析
如果每次只问一条边,我们可以用树剖或树上倍增找到这条链上最大值再替换成询问的边,但现在询问为一个集合,因此问题复杂很多。
关于kruskal有两个很有趣的定理
- 定义wi为每一条边,对于任意wi,我们选择长度<wi的边构成的联通块是相同的
- 定义最小生成树中边长为wi的边条数有ci条,对于所有的最小生成树来说,wi和ci都是相同的
考虑离线的处理方法,我们把所有询问的边按照权值进行分类,这样就可以做到在处理长度为wi的边时,长度<wi的边都已经处理完成了,如果我们当时加入权值为wi的边时发现构成环,说明这条边是不必要的,因此可以直接标记这个询问为false。但我们发现,相同权值的边处在不同的询问当中,因此我们在处理完一个询问的时候要撤销之前的影响,用可撤销并查集就可以解决。
AC Code
#include <bits/stdc++.h>
//#define ACM_LOCAL
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 5e5 + 10, M = 5e5 + 10, INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int n, m, k, cnt;
struct Edge
int u, v, w;
bool operator < (const Edge &rhs) const
return w < rhs.w;
e[N];
struct Query
int u, v, id;
bool operator < (const Query &rhs) const
return id < rhs.id;
;
bool ans[N];
vector<Query> vec[N];
struct Undo_dsu
stack<PII> st;
int fa[N], siz[N];
void init()
while (st.size()) st.pop();
for (int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1;
int find(int x) return fa[x] == x ? x : find(fa[x]);
bool merge(int x, int y)
int fx = find(x), fy = find(y);
if (fx == fy) return false;
if (siz[fx] > siz[fy]) swap(fx, fy), swap(x, y);
siz[fy] += siz[fx], fa[fx] = fy;
st.push(fx, fy);
return true;
void undo()
PII now = st.top();
fa[now.fi] = now.fi;
siz[now.se] -= siz[now.fi];
st.pop();
dsu;
void solve()
cin >> n >> m; dsu.init();
for (int i = 1; i <= m; i++) cin >> e[i].u >> e[i].v >> e[i].w;
cin >> k; for (int i = 1; i <= k; i++)
int num; cin >> num;
while (num--)
int x; cin >> x;
vec[e[x].w].push_back(e[x].u, e[x].v, i);
for (int i = 1; i <= N-10; i++) if(vec[i].size()) sort(vec[i].begin(), vec[i].end());
for (int i = 1; i <= k; i++) ans[i] = true;
sort(e + 1, e + m + 1);
for (int i = 1; i <= m; )
int val = e[i].w, now = dsu.st.size();
for (int j = 0; j < vec[val].size(); j++)
if (!ans[vec[val][j].id]) continue;
if (j && vec[val][j].id != vec[val][j-1].id)
while (dsu.st.size() > now) dsu.undo();
if (!dsu.merge(vec[val][j].u, vec[val][j].v)) ans[vec[val][j].id] = false;
while (e[i].w == val) dsu.merge(e[i].u, e[i].v), i++;
for (int i = 1; i <= k; i++) printf("%s\\n", ans[i] ? "YES" : "NO");
int main()
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
#endif
solve();
return 0;
以上是关于CF 891C Envy 最小生成树+可撤销并查集的主要内容,如果未能解决你的问题,请参考以下文章