ICPC 澳門賽站 K.Link-Cut Tree
阿新 • • 發佈:2022-04-04
ICPC 澳門賽站
K.Link-Cut Tree
題意:給你\(n\)個點,\(m\)條邊,第\(i\)條邊的長度是\(2^i\),問你在所給的所有邊中能形成的權值最小的環的邊的下標,如果不能形成環則輸出\(-1\)。
思路:先讀入所有的邊,然後貪心選擇前面的邊,利用並查集看當前的連個點是否在一個連通塊裡面,如果在就\(dfs\)回去找環,如果不在就合併集合。類似於\(Kruskal\)的思想。如何找邊的下標,讀入的時候記錄以下邊的下標,然後回溯的時候之前來的那條邊不能回溯,其餘就深搜回去,一直找到那個最終目標即可。
#include <bits/stdc++.h> #define PII pair<int,int> #define LL long long #define fi first #define debug(x) cout << #x << " = " << x << endl; #define se second #define all(x) (x).begin(),(x).end() #define pb push_back #define sz(x) (int)x.size() #define INF 2e9 #define mod 998244353 using namespace std; const int N = 100010; int n, m; int x[N], y[N]; int p[N]; vector<PII>v[N]; vector<int>ans; int find(int x){ if(p[x] != x) p[x] = find(p[x]);c return p[x]; } bool st[N], ok; int cnt = 0; void dfs(int u, int cur, int vv){ cnt ++; if(u == vv){ int k = sz(ans); sort(all(ans)); for(int i = 0; i < k; i ++ ){ if(i < k - 1) printf("%d ",ans[i]); else printf("%d",ans[i]); } cout << "cnt = " << cnt << endl; } st[u] = true; for(auto [x, y] : v[u]) { if(x != cur){ ans.pb(y); dfs(x, u, vv); ans.pop_back(); cnt ++; } } } void solve() { scanf("%d %d",&n, &m); ans.clear(); ok = false; for(int i = 1; i <= m; i ++ ){ scanf("%d %d",&x[i], &y[i]); } for(int i = 1; i <= n; i ++ ){ p[i] = i; v[i].clear(); } bool ok = false; int index; for(int i = 1; i <= m; i ++ ){ int xx = find(x[i]), yy = find(y[i]); if(xx == yy){ ans.pb(i); dfs(x[i], 0, y[i]); return; } p[xx] = yy; v[x[i]].pb(make_pair(y[i], i)); v[y[i]].pb(make_pair(x[i], i)); } printf("-1"); } int main() { int test = 1; scanf("%d",&test); while(test -- ) { solve(); if(test) puts(""); } return 0; }