Link-Cut Tree
传送门
本题是找第一次出现的环;
题面
思路
二进制有一个常见的性质 2 1 + 2 2 + . . . + 2 i < 2 i + 1 2^1+2^2+...+2^i <2^{i+1} 21+22+...+2i<2i+1
那么本题其实也就是要我们求第一次出现的环;
那么考虑用并查集来处理(类似Kruskal),然后dfs
一次;
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
struct Node{
int v,w;
};
vector<Node> G[N];
int f[N],n,m;
int find(int x){
if(x == f[x]) return x;
return f[x] = find(f[x]);
}
bool merge(int u,int v){
int fu = find(u),fv = find(v);
if(fu == fv) return 0;
f[fu] = fv;
return 1;
}
vector<int> path;
bool dfs(int u,int fa,int end){
if(u == end) return 1;
bool ret = 0;
for(auto to : G[u]){
int v = to.v,w = to.w;
if(v != fa && dfs(v,u,end)){
path.push_back(w);
ret = 1;
}
}
return ret;
}
void solve(){
path.clear();
cin >> n >> m;
for(int i=1;i<=n;++i){
f[i] = i;
G[i].clear();
}
bool flag = 0;
for(int i=1;i<=m;++i){
int u,v,w;
cin >> u >> v;
w = i;
if(flag) continue;
bool ff = merge(u,v);
if(!ff){//遇到环了
flag = 1;
path.push_back(w);
dfs(u,-1,v);
}
else{
G[u].push_back({v,w});
G[v].push_back({u,w});
}
}
if(!flag){
cout << -1 << '\n';
}
else{
sort(path.begin(),path.end());
int sz = path.size();
for(int i=0;i<sz-1;++i) cout << path[i] << ' ';
cout << path.back() << '\n';
}
}
signed main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin >> t;
while(t--)
solve();
return 0;
}