https://codeforces.com/problemset/problem/1250/N
这场vp到2个半小时机房断网了。。。C都没来得及写。。。。这题也没调。。。
这题当时WA43,大致思路就是把联通块找出来,然后把其他连通块都连向第一个连通块
对于如果这个连通块存在du为1的点,那么我们就舍弃这个点,把这条边连向第一个连通块
如果不存在,我比赛的时候脑抽以为因为du全都>=2所以每个点都是在环上所以可以随便选,其实是du>=2也有可能是割点,任选一条边有可能选到割边的,所以只需要在dfs的时候记录一下这个联通分量中的任意一条环上的边就行了。
#include<bits/stdc++.h>
#define maxl 200010
using namespace std;
int n,m,cnt,tot,fcnt;
int num[maxl],ehead[maxl],du[maxl],huan[maxl];
vector<int> f[maxl];
struct edge
{
int u,v;
}inie[maxl];
struct ed
{
int to,nxt,id;
}e[maxl<<1];
bool vis[maxl];
struct q
{
int id,a,b;
}ans[maxl];
inline void add(int u,int v,int id)
{
e[++cnt].to=v;e[cnt].id=id;
e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
inline void dfs(int u,int fa)
{
vis[u]=true;f[fcnt].push_back(u);
int v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(v==fa) continue;
if(vis[v])
huan[fcnt]=e[i].id;
else
dfs(v,u);
}
}
inline void prework()
{
scanf("%d",&m);
int u,v;tot=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
inie[i]=edge{u,v};
num[++tot]=u;
num[++tot]=v;
}
sort(num+1,num+1+tot);
n=unique(num+1,num+1+tot)-num-1;
for(int i=1;i<=n;i++)
ehead[i]=0,du[i]=0,vis[i]=false;
cnt=0;
for(int i=1;i<=m;i++)
{
u=lower_bound(num+1,num+1+n,inie[i].u)-num;
v=lower_bound(num+1,num+1+n,inie[i].v)-num;
add(u,v,i);add(v,u,i);
du[u]++;du[v]++;
}
for(int i=1;i<=fcnt;i++)
f[i].clear();
fcnt=0;
for(int i=1;i<=n;i++)
if(!vis[i])
{
fcnt++;
dfs(i,0);
}
}
inline void mainwork()
{
if(fcnt==1)
return;
else
{
int u,v,l;
for(int i=2;i<=fcnt;i++)
{
l=f[i].size();u=-1;
for(int j=0;j<l;j++)
if(du[f[i][j]]==1)
u=f[i][j];
if(u>0)
{
ans[i-1].id=e[ehead[u]].id;
ans[i-1].a=num[u];
ans[i-1].b=num[f[1][0]];
}
else
{
ans[i-1].id=huan[i];
ans[i-1].a=inie[huan[i]].u;
ans[i-1].b=num[f[1][0]];
}
}
}
}
inline void print()
{
if(fcnt==1)
puts("0");
else
{
printf("%d\n",fcnt-1);
for(int i=1;i<=fcnt-1;i++)
printf("%d %d %d\n",ans[i].id,ans[i].a,ans[i].b);
}
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}