Codeforces Round #446(Div.2)Problem E Envy(并查集)

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".



【思路】

题目给了一个有边权的无向图,然后给若干组边,问是否有最小生成树能包含这些边。首先引入性质:任意两棵最小生成树的有序边权列表必定相同。考虑Kruskal算法的过程,在生成最小生成树的某一时刻会形成若干点集(树),它们内部都是以尽可能短的边相连的,我们称之为最小生成森林,设此时用上的边中最长的那条长度为x,那么如果此时用大于x的边连接同一点集的两个点必不可行。所以必须能够动态维护维护最小生成森林(在此学习了一波可撤销的并查集),所谓可撤销就是当新一轮的询问到来或研究更大的边权之时,把当前边的两端点复原至最小生成森林各自的子集中,这样就能判断是否会形成环,继而判断这组边是否可行。


【代码】

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int MAXN = 5e5 + 5;

struct edge {
    int from, to, dist;
};

int n, m, q, cnt;
int fa_1[MAXN], fa_2[MAXN], kase[MAXN];
bool wa[MAXN];
edge e[MAXN];
vector<int> gra[MAXN];
vector<pair<int, int> > qr[MAXN];

int findfather_1(int x)
{
    return (fa_1[x] == x ? x : fa_1[x] = findfather_1(fa_1[x]));
}

int findfather_2(int x)
{
    if (kase[x] != cnt) {kase[x] = cnt; fa_2[x] = findfather_1(x);}
    return (x == fa_2[x] ? x : fa_2[x] = findfather_2(fa_2[x]));
}

int main()
{
    scanf("%d %d", &n, &m);
    int a, b, c, mx = 0;
    for (int i = 1; i <= m; i++) {
        scanf("%d %d %d", &a, &b, &c);
        e[i].from = a;
        e[i].to = b;
        e[i].dist = c;
        gra[c].push_back(i);
        mx = max(mx, c);
    }
    int k, x;
    scanf("%d", &q);
    for (int i = 1; i <= q; i++) {
        scanf("%d", &k);
        for (int j = 1; j <= k; j++) {
            scanf("%d", &x);
            qr[e[x].dist].push_back(make_pair(i, x));
        }
    }
    memset(wa, false, sizeof(wa));
    memset(kase, 0, sizeof(kase));
    for (int i = 1; i <= n; i++) fa_1[i] = i;
    cnt = 0;
    for (int i = 1; i <= mx; i++) {
        sort(qr[i].begin(), qr[i].end());
        for (int j = 0; j < qr[i].size(); j++) {
            if (j == 0 || qr[i][j].first != qr[i][j - 1].first) cnt++;
            int x = findfather_2(e[qr[i][j].second].from);
            int y = findfather_2(e[qr[i][j].second].to);
            if (x == y) wa[qr[i][j].first] = true;
            fa_2[y] = x;
        }
        for (int j = 0; j < gra[i].size(); j++) {
            int x = findfather_1(e[gra[i][j]].from);
            int y = findfather_1(e[gra[i][j]].to);
            fa_1[y] = x;
        }
    }
    for (int i = 1; i <= q; i++)
        printf(!wa[i] ? "YES\n" : "NO\n");
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的精简博客系统,源码+数据库+毕业论文+视频演示 当下,正处于信息化的时代,许多行业顺应时代的变化,结合使用计算机技术向数字化、信息化建设迈进。以前企业对于博客信息的管理和控制,采用人工登记的方式保存相关数据,这种以人力为主的管理模式已然落后。本人结合使用主流的程序开发技术,设计了一款基于Springboot开发的精简博客系统,可以较大地减少人力、财力的损耗,方便相关人员及时更新和保存信息。本系统主要使用B/S开发模式,在idea开发平台上,运用Java语言设计相关的系统功能模块,MySQL数据库管理相关的系统数据信息,SpringBoot框架设计和开发系统功能架构,最后通过使用Tomcat服务器,在浏览器中发布设计的系统,并且完成系统与数据库的交互工作。本文对系统的需求分析、可行性分析、技术支持、功能设计、数据库设计、功能测试等内容做了较为详细的介绍,并且在本文中也展示了系统主要的功能模块设计界面和操作界面,并对其做出了必要的解释说明,方便用户对系统进行操作和使用,以及后期的相关人员对系统进行更新和维护。本系统的实现可以极大地提高企业的工作效率,提升用户的使用体验,因此在现实生活中运用本系统具有很大的使用价值。 关键词:博客管理;Java语言;B/S结构;MySQL数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值