Codeforces Round #446 (Div. 2) E. Envy

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值