https://codeforces.com/contest/858/problem/F
一开始看错题了,以为是一个联通块只能从一个地方出发,走最多的点,边双缩点后树形dp求每个连通块的最长路径,以后读完题还是看看样例比较好
结果发现必须是长度为2的路径
那么就直接dfs树了,从最底下开始处理完所有儿子后向上,先找到当前节点u所有的还有没连满的儿子节点v,就u->v->a[v]成一次。然后再对于那些连满的儿子,直接两个两个分,v1->u->v2这样。最后如果有剩下的v,说明u的所有儿子还没有解决,a[u]=v,交给u的父亲到u的边去处理
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,ans,cas,k,cnt,tot,dcc,ind,mx;
int a[maxl],dep[maxl];
vector<int> e[maxl],res[maxl];
bool vis[maxl],in[maxl];
struct node
{
int x,y,z;
}b[maxl];
inline void prework()
{
scanf("%d%d",&n,&m);
cnt=1;int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
}
inline void dfs(int u,int fa)
{
vis[u]=true;res[u].clear();
for(int v:e[u])
{
if(v==fa) continue;
if(vis[v])
{
if(dep[v]<dep[u])
res[u].push_back(v);
continue;
}
dep[v]=dep[u]+1;
res[u].push_back(v);
dfs(v,u);
}
for(int v:res[u]) in[v]=true;
int last,len=res[u].size();
for(int v:res[u])
if(a[v]>0)
{
b[++ans]=node{u,v,a[v]};
a[v]=0;in[v]=false;
}
last=0;
for(int v:res[u])
if(in[v])
{
if(last)
b[++ans]=node{last,u,v},last=0;
else
last=v;
in[v]=false;
}
if(last>0)
a[u]=last;
}
inline void mainwork()
{
for(int i=1;i<=n;i++)
if(!vis[i])
dfs(i,0);
}
inline void print()
{
printf("%d\n",ans);
for(int i=1;i<=ans;i++)
printf("%d %d %d\n",b[i].x,b[i].y,b[i].z);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}