E. Envy
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
For a connected undirected weighted graph G, MST (minimum spanning tree) is a subgraph of G that contains all of G’s vertices, is a tree, and sum of its edges is minimum possible.
You are given a graph G. If you run a MST algorithm on graph it would give you only one MST and it causes other edges to become jealous. You are given some queries, each query contains a set of edges of graph G, and you should determine whether there is a MST containing all these edges or not.
Input
The first line contains two integers n, m (2 ≤ n, m ≤ 5·105, n - 1 ≤ m) — the number of vertices and edges in the graph and the number of queries.
The i-th of the next m lines contains three integers ui, vi, wi (ui ≠ vi, 1 ≤ wi ≤ 5·105) — the endpoints and weight of the i-th edge. There can be more than one edges between two vertices. It’s guaranteed that the given graph is connected.
The next line contains a single integer q (1 ≤ q ≤ 5·105) — the number of queries.
q lines follow, the i-th of them contains the i-th query. It starts with an integer ki (1 ≤ ki ≤ n - 1) — the size of edges subset and continues with ki distinct space-separated integers from 1 to m — the indices of the edges. It is guaranteed that the sum of ki for 1 ≤ i ≤ q does not exceed 5·105.
Output
For each query you should print “YES” (without quotes) if there’s a MST containing these edges and “NO” (of course without quotes again) otherwise.
Example
input
5 7
1 2 2
1 3 2
2 3 1
2 4 1
3 4 1
3 5 2
4 5 2
4
2 3 4
3 3 4 5
2 1 7
2 1 2
output
YES
NO
YES
NO
题意就是用提问的点构造mst,首先有一个结论,对于用一个q里面的k,不同权值之间没有影响。然后对于一个权值的边,先在原图中跑mst,直到当前边大于等于权值。然后跑并查集,如果产生环,那么这个q就是false。然后在把并查集恢复到以前的状态。
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+100;
int f[N];
struct node{
int u,v,w;
bool operator<(const node &a)const{
return w < a.w;
}
};
struct qq{
int id,u,v,w;
bool operator<(const qq& a)const{
if(a.w == w) return id < a.id;
return w < a.w;
}
};
vector<pair<int,int> > v;
qq q[N];
node pt[N];
bool vis[N];
int Find(int x,bool tmp){
if(tmp) v.push_back({x,f[x]});
return x == f[x] ? x : f[x] = Find(f[x],tmp);
}
int main(){
int n,m;
cin >> n>> m;
for(int i = 1; i<= m;i ++){
scanf("%d %d %d",&pt[i].u,&pt[i].v,&pt[i].w);
}
int qs;
cin >> qs;
int tot = 0;
for(int i = 1;i <= qs;i ++){
int k;
scanf("%d",&k);
for(int j = 1;j <= k;j ++){
q[tot].id = i;
int now;
scanf("%d",&now);
q[tot].u = pt[now].u;
q[tot].v = pt[now].v;
q[tot].w = pt[now].w;
tot ++;
}
}
sort(q,q+tot);
sort(pt+1,pt+1+m);
int cnt = 0;
for(int i = 1;i <= n;i ++) f[i] = i;
for(int i = 1;i <= m;i ++){
while(cnt <tot && q[cnt].w == pt[i].w){
queue<qq> que;
que.push(q[cnt]);
int tmp = q[cnt].id;
for(int j = cnt+1;j <= tot;j ++){
if(q[j].w == q[j-1].w && q[j].id == q[j-1].id) que.push(q[j]);
else {cnt = j;break;}
}
bool res = true;
while(!que.empty()){
qq now = que.front();
que.pop();
int f1 = Find(now.u,true);
int f2 = Find(now.v,true);
if(f1 == f2){
res = false;
break;
}
f[f1] = f2;
v.push_back({f1,f1});
}
if(res == false) vis[tmp] = true;
for(int i = v.size()-1;i >= 0;i --){
f[v[i].first] = v[i].second;
}
v.clear();
}
int f1 = Find(pt[i].u,false);
int f2 = Find(pt[i].v,false);
if(f1 == f2) continue;
f[f1] = f2;
}
int cns = 0;
for(int i = 1;i <= n;i ++) if(Find(i,false) == i) cns ++;
if(cns >= 2) {
for(int i = 1;i <= qs;i ++){
puts("NO");
}
}
else {
for(int i = 1;i <= qs;i ++){
if(vis[i]) puts("NO");
else puts("YES");
}
}
return 0;
}