问题如标题
解法思路:先类似克鲁斯卡尔按顺序合并每条边,将一条边的端点改为合并了边权小于此边的所有边后端点所在并查寄的顶点,对于每个查询直接合并查询的边修改后的端点,有环则不行,没环则可以
代码:
#include<bits/stdc++.h>
#define x first
#define y second
#define pii pair<int, int>
#define vci vector<int>
#define psb push_back
using namespace std;
int p[500005][2];
vci hd[2];
void init(){
for(int i = 1; i <= 500000; i++) p[i][0] = p[i][1] = i;
}
int find(int op, int u){
if(u == p[u][op]) return u;
return p[u][op] = find(op, p[u][op]);
}
bool mer(int op, int a, int b){
a = find(op, a), b = find(op, b);
if(a == b) return 0;
hd[op].psb(a), hd[op].psb(b);
p[a][op] = b;
return 1;
}
void clr(int op){
for(int i = 0; i < hd[op].size(); i++) p[hd[op][i]][op] = hd[op][i];
hd[op].clear();
}
int n, m, q;
vci hv[500005];
pair<pii, int> e[500005];
signed main(){
//ios::sync_with_stdio(false);
//cin.tie(NULL);
//cout.tie(NULL);
//freopen(".in", "r", stdin);
//freopen(".out", "w", stdout);
srand(time(0));
init();
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) scanf("%d%d%d", &e[i].x.x, &e[i].x.y, &e[i].y), hv[e[i].y].psb(i);
for(int i = 1; i <= 500000; i++){
for(int j : hv[i]) e[j].x.x = find(0, e[j].x.x), e[j].x.y = find(0, e[j].x.y);
for(int j : hv[i]) mer(0, e[j].x.x, e[j].x.y);
}
cin >> q;
while(q--){
int x, fl = 1;
scanf("%d", &x);
while(x--){
int id;
scanf("%d", &id);
fl &= mer(1, e[id].x.x, e[id].x.y);
}
if(fl) puts("YES");
else puts("NO");
clr(1);
}
return 0;
}