Codeforces 892/E Envy 最小生成树的query

E. Envy
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard 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 nm (2  ≤ n, m  ≤ 5·105n - 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 uiviwi (ui ≠ vi1 ≤ 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
Note

This is the graph of sample:

Weight of minimum spanning tree on this graph is 6.

MST with edges (1, 3, 4, 6), contains all of edges from the first query, so answer on the first query is "YES".

Edges from the second query form a cycle of length 3, so there is no spanning tree including these three edges. Thus, answer is "NO".

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;

const int N=501000;

int n,m,u[N],v[N],w[N],f[N],p[N],qrcase[N],T,wa[N];
int Q,k,id,x,maxw;
vector<int> eg[N];
vector<PII> qw[N];
int nxt1[N], nxt2[N];


int find1(int now){
    if (nxt1[now]==now) return now;
    return nxt1[now]=find1(nxt1[now]);
}

int find2(int now){
    if (qrcase[now]!=T){qrcase[now]=T; nxt2[now]=nxt1[now];}
    if (nxt2[now]==now) return now;
    return nxt2[now]=find2(nxt2[now]);
}
int main() {
    maxw=0;
	scanf("%d%d",&n,&m);
    for (int i=1; i<=m; i++){
        scanf("%d%d%d", u+i, v+i, w+i);
        eg[w[i]].push_back(i);
        maxw=max(maxw, w[i]);
    }

    scanf("%d", &Q);
    for (int i=0; i<Q; i++){
        scanf("%d", &id);
        for (int j=0; j<id; j++){
            scanf("%d", &x);
            qw[w[x]].push_back(mp(i, x));
        }
    }

    memset(wa, 0, sizeof(wa));

    for (int i=1; i<=n; i++){
        nxt1[i]=i;
    }
    T=0;
    for (int i=1; i<=maxw; i++){
        sort(qw[i].begin(), qw[i].end());
        for (int j=0; j<qw[i].size(); j++){
            if (j==0 || qw[i][j].first!=qw[i][j-1].first) T++;
            int x=u[qw[i][j].second], y=v[qw[i][j].second];
            if (find2(x)==find2(y)){
                wa[qw[i][j].first]=true;
            }
            nxt2[find2(y)]=nxt2[find2(x)];///nxt2[y]=x;
        }
        for (int j=0; j<eg[i].size(); j++){
            int x=find1(u[eg[i][j]]); int y=find1(v[eg[i][j]]);
            nxt1[find1(y)]=find1(x);
        }
    }
    for (int i=0; i<Q; i++){
        if (wa[i]) printf("NO\n"); else printf("YES\n");
    }
}

两个注意点

第一点是原理,按照边权值由小到大的顺序,处理每个query的边。用两个并查集,第一个并查集next1是原图所有边,第二个是每个query的边。保证处理query边的时候原图的权值小的边已经处理过了,如图1,这样一旦有回路说明可以用小的边来替换当前query的边,就不存在了,不然就是存在的!

第二点,注意并查集的next数组的更新。

再传一个别人写的

题目大意: 给出一个n个顶点, m条边的联通无向图, 每条边有权值 wi ,有q组询问, 每次询问原图中的 ki 条边, 求是否存在一种最小生成树包含这 ki 条边。 (n,m,wi,q,ki5105)

思路: 考虑离线求解。 先将所有边按从小到大排序, 每次同时考虑一堆权值均为x的边, 根据kruskal算法, 所有 < x的边已经进行了并查集缩点, 再单独考虑所有涉及了这一次权值为x的询问 qi , 把 qi 涉及到的边单独拿出来做并查集合并, 若出现了环则 qi 这条询问判断为不存在, 再把这次的修改还原, 考虑完所有的涉及到的询问后, 把该层权值为x的边端点并查集合并后, 继续考虑下一层权值的边。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您提供的链接是Codeforces的一个问题,问题编号为104377。Codeforces是一个知名的在线编程竞赛平台,经常举办各种编程比赛和训练。Gym是Codeforces的一个扩展包,用于组织私人比赛和训练。您提供的链接指向了一个问题的页面,但具体的问题内容和描述无法通过链接获取。如果您有具体的问题或需要了解关于Codeforces Gym的更多信息,请提供更详细的信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [http://codeforces.com/gym/100623/attachments E题](https://blog.csdn.net/weixin_30820077/article/details/99723867)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [http://codeforces.com/gym/100623/attachments H题](https://blog.csdn.net/weixin_38166726/article/details/99723856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [CodeforcesPP:Codeforces扩展包](https://download.csdn.net/download/weixin_42101164/18409501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值