题解 CF589H 【Tourist Guide】
【CF589H】Tourist Guide
先考虑一棵树的情况。容易发现,只要关键点数量为偶数个,那一定存在某种匹配方式,能将它们两两匹配成功。树已如此,图就更应该如此了。
所以我们可以轻易算出匹配对数。令size[p]表示第p个联通块中关键点的数量,则答案为Σ(size[p] / 2)
考虑到图上方案很难输出,树上相对容易一些,而把图变成树并不影响两两匹配成功的事实,于是我们可以把图的生成树造出来,随便生成一棵树即可
然后直接搜索即可。记fuck[x]表示节点x及其下方第一个未匹配的点,然后在子树中遇到一个可匹配的点就匹配上去。如果子树中仍然存在未匹配的点,就将fuck[x]传给它的父亲
路径的输出直接暴力跳到LCA即可,沿途记录经过的点
#include<bits/stdc++.h>
using namespace std;
namespace IO
{
const int S=(1<<20)+5;
char buf[S],*H,*T;
inline char Get()
{
if(H==T) T=(H=buf)+fread(buf,1,S,stdin);
if(H==T) return -1;return *H++;
}
inline int read()
{
int x=0;char c=Get();
while(!isdigit(c)) c=Get();
while(isdigit(c)) x=x*10+c-'0',c=Get();
return x;
}
char obuf[S],*oS=obuf,*oT=oS+S-1,c,qu[55];int qr;
inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
inline void putc(char x){*oS++ =x;if(oS==oT) flush();}
template <class I>inline void print(I x)
{
if(!x) putc('0');
while(x) qu[++qr]=x%10+'0',x/=10;
while(qr) putc(qu[qr--]);
}
}
using IO::read;
using IO::print;
using IO::putc;
const int N=50010;
struct Edge{int to,next;} e[N<<1];
int h[N],sum=0,n,m,tot;
int dep[N],fa[N],fuck[N];
int ffa[N],sz[N];
bool spd[N];
int find(int x){return ffa[x]==x?x:ffa[x]=find(ffa[x]);}
void add_edge(int u,int v)
{
e[++sum].to=v;
e[sum].next=h[u];
h[u]=sum;
}
void getpath(int x,int y)
{
static int path1[N],path2[N];
int tot1=0,tot2=0;
while(x!=y)
{
if(dep[x]>dep[y]) path1[++tot1]=x,x=fa[x];
else path2[++tot2]=y,y=fa[y];
}
path1[++tot1]=x;
print(tot1+tot2-1);putc(' ');
for(int i=1;i<=tot1;i++) print(path1[i]),putc(' ');
for(int i=tot2;i>=1;i--) print(path2[i]),putc(' ');
putc('\n');
}
void dfs(int u,int la)
{
fuck[u]=spd[u]?u:0;
for(int t=h[u];t;t=e[t].next)
{
int v=e[t].to;
if(v==la) continue;
dep[v]=dep[u]+1;
fa[v]=u;dfs(v,u);
if(!fuck[v]) continue;
if(!fuck[u]) fuck[u]=fuck[v];
else getpath(fuck[u],fuck[v]),fuck[u]=0;
}
}
int main()
{
n=read();m=read();tot=read();
for(int i=1;i<=n;i++) ffa[i]=i;
for(int i=1,u,v;i<=m;i++)
{
u=read();v=read();
if(find(u)==find(v)) continue;
ffa[find(u)]=find(v);
add_edge(u,v);
add_edge(v,u);
}
for(int i=1,x;i<=tot;i++)
x=read(),spd[x]=1,sz[find(x)]++;
int ans=0;
for(int i=1;i<=n;i++)
if(ffa[i]==i) ans+=sz[i]/2;
print(ans);putc('\n');
for(int i=1;i<=n;i++)
if(ffa[i]==i) dfs(i,0);
IO::flush();
return 0;
}