1. 程式人生 > >Codeforces 892/E Envy 最小生成樹的query

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 graphG, MST (minimum spanning tree) is a subgraph ofGthat contains all ofG's vertices, is a tree, and sum of its edges is minimum possible.

You are given a graphG. 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 graphG

, and you should determine whether there is a MST containing all these edges or not.

Input

The first line contains two integersn,m(2  ≤ n, m  ≤ 5·105,n - 1 ≤ m) — the number of vertices and edges in the graph and the number of queries.

Thei-th of the nextmlines contains three integersui,vi,wi(u

i ≠ vi,1 ≤ wi ≤ 5·105) — the endpoints and weight of thei-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 integerq(1 ≤ q ≤ 5·105) — the number of queries.

qlines follow, thei-th of them contains thei

-th query. It starts with an integerki(1 ≤ ki ≤ n - 1) — the size of edges subset and continues withkidistinct space-separated integers from1tom — the indices of the edges. It is guaranteed that the sum ofkifor1 ≤ i ≤ qdoes not exceed5·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 is6.

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 length3, 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的邊端點並查集合並後, 繼續考慮下一層權值的邊。