题目大意
题解
一开始想dp,然后想不出来直接大力猜结论+胡乱构造
显然答案上界是Σmin(2,边i覆盖次数),手玩样例发现可以构出来且举不出反例
考虑构造,显然需要决策的只有覆盖次数>=2的边,则每次把经过这类边剩余路径最少的那条拿出来,随便找一条经过其的路径定向并更新,这样一定可以构出来,然后发现现在并不会证了
题解做法:每次找叶子,把经过其父亲边的链(u,a)和(u,b)找出,将其变成(u,a)和(a,b),然后(u,b)的方向取决于(a,b)的方向,这样就可以不断往上删了
关于上面的奇妙做法,在值相同时把编号随机赋权交了3次都过了,所以应该是对的
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define pd(x,y) (bg[x]<=bg[y] && ed[y]<=ed[x])
#define ll long long
//#define file
using namespace std;
int rd[2001];
struct type{int s,x;} s;
bool operator < (type a,type b) {return !(a.s<b.s || a.s==b.s && rd[a.x]<rd[b.x]);}
priority_queue<type> hp;
int n,m,i,j,k,l;
int a[4001][2],ls[2001],len,fa[2001],d[2001];
int b[2001][2],bg[2001],ed[2001];
int ans[2001],bz[2001],Ans,sum[2001];
vector<int> c[2001];
void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
void swap(int &x,int &y) {int z=x;x=y;y=z;}
void dfs(int Fa,int t)
{
int i;
fa[t]=Fa,d[t]=d[Fa]+1,bg[t]=++j;
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
dfs(t,a[i][0]);
ed[t]=j;
}
void add(int x,int y,int s)
{
while (!pd(x,y)) c[x].push_back(s),++sum[x],x=fa[x];
while (x!=y) c[y].push_back(s),++sum[y],y=fa[y];
}
void change(int x,int y,int s)
{
while (!pd(x,y)) {--sum[x];if (sum[x]>0) hp.push(type{sum[x],x}); bz[x]|=s;x=fa[x];}
while (x!=y) {--sum[y];if (sum[y]>0) hp.push(type{sum[y],y}); bz[y]|=3-s;y=fa[y];}
}
int main()
{
#ifdef file
freopen("agc025E.in","r",stdin);
#endif
srand(time(NULL));
scanf("%d%d",&n,&m);
fo(i,1,n) rd[i]=i;
random_shuffle(rd+1,rd+n+1);
fo(i,1,n-1) scanf("%d%d",&j,&k),New(j,k),New(k,j);
j=0,dfs(0,1);
fo(i,1,m) {scanf("%d%d",&b[i][0],&b[i][1]);if (b[i][0]>b[i][1]) swap(b[i][0],b[i][1]);add(b[i][0],b[i][1],i);}
fo(i,2,n)
{
l=sum[i];
Ans+=(l>0)+(l>1);
if (l>1) hp.push(type{l,i});
}
while (!hp.empty())
{
s=hp.top();hp.pop();
if (bz[s.x]==3) continue;
if (!bz[s.x] || bz[s.x]==2) l=1;
else l=2;
bz[s.x]|=l;
do{
k=c[s.x].back(),c[s.x].pop_back();
} while (ans[k]);
if (pd(s.x,b[k][0])) ans[k]=l;
else ans[k]=3-l;
change(b[k][0],b[k][1],ans[k]);
}
printf("%d
",Ans);
fo(i,1,m)
if (ans[i]==1)
printf("%d %d
",b[i][0],b[i][1]);
else
printf("%d %d
",b[i][1],b[i][0]);
fclose(stdin);
fclose(stdout);
return 0;
}