agc025E

题目大意

题解

一开始想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;
}
原文地址:https://www.cnblogs.com/gmh77/p/14040250.html