Atcoder题解:Arc156_c

数据范围 \(5\cdot 10^3\),但是介绍一个 \(O(n\log n)\) 做法。

我们考虑观察样例,发现样例都很小,而且 \(\text{LCS}\) 的长度都是 \(1\),那么我们就猜答案最多为 \(1\),并尝试去构造。

我们画一个链,发现链上的统配解就是倒过来。那么我们考虑普通的树,我们发现,普通的树比链的性质更强一些。

我们可以找到树的重心,将其分割成若干个子树。然后安排每个子树中的值到别的地方去。这样可以保证每个子树中的数都在别的子树中。

然后,我们需要按照拓扑序倒着往里填。例如,子树 \(A\)\(x\) 在最上面,填进子树 \(B\) 的时候 \(x\) 也要在最上面。如此,在任何的 \(x\) 链上,\(x\)\(x\) 子树中的值都是逆序出现的,最多造成 \(1\) 的贡献。

如果树有两个重心,从重心边分成两棵树直接填充。

如果树只有一个重心,将所有分割出的子树从重心开始的 \(\text{dfs}\) 序跑出来存在 \(\text{vector}\) 里面,每次找到最大的两个 \(\text{vector}\) 进行配对。我们发现,如果我们可以把 \(x\) 放在 \(y\),也可以把 \(y\) 放在 \(x\)。这样,因为是重心,剩下的节点最多只有 \(1\) 个,如果剩下了,就和重心配对,否则重心和自己配对。

为什么重心当根就一定能匹配到只剩 \(0\)\(1\) 个结点?

因为是重心当根,就没有一个分出来的子树多于 \(dfrac{n}{2}\) 个节点。应用数学归纳法,\(n=2\)\(n=3\) 时,结论显然成立。然后当前点数 \(n>3\),最大子树小于 \(dfrac{n}{2}\) 的情况中,在最大的子树中找一个点,再随便找一个别的点,此时 \(n'=n-2\),且最大子树的点数依然不超过 \(\dfrac{n'}{2}\),得证。

每次找到最大的 \(\text{vector}\) 需要使用 \(\text{priority_queue}\) 维护 \(\text{vector}\) 大小和下标,每次弹出后更新大小加入。总复杂度 \(O(n\log n)\)


int n,sz[5005],a,b,pa[5005];
vt<int>vv[5005];
inline void dfs(int x,int p){
	sz[x]=1,pa[x]=p;
	for(auto j:vv[x])if(j!=p){
		dfs(j,x);sz[x]+=sz[j];
	}
}
inline int cen(int x,int p){
	for(auto j:vv[x])if(j!=p){
		if(sz[j]*2>=n)return cen(j,x);
	}
	return x;
}
inline void dfss(int x,int p,vt<int>&v){
	v.pb(x);
	for(auto j:vv[x])if(j!=p){
		dfss(j,x,v);
	}
}
int ans[5005];
inline void solve1(int r){
	vt<vt<int> >vs;
	ans[r]=r;
	for(auto j:vv[r]){
		vt<int>v;
		dfss(j,r,v);
		vs.pb(v);
	}
	priority_queue<pii>pq;
	rd(i,vs.size())pq.push({vs[i].size(),i});
	while(pq.size()){
		if(pq.size()==1){
			int x=pq.top().second;pq.pop();
			ans[vs[x].back()]=r;
			ans[r]=vs[x].back();
			break;
		}
		int x=pq.top().second;pq.pop();
		int y=pq.top().second;pq.pop();
		ans[vs[x].back()]=vs[y].back();
		ans[vs[y].back()]=vs[x].back();
		vs[x].pop_back();vs[y].pop_back();
		if(vs[x].size())pq.push({vs[x].size(),x});
		if(vs[y].size())pq.push({vs[y].size(),y});
	}
	rp(i,n)cout<<ans[i]<<" ";
	cout<<endl;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	rp(i,n-1){
		cin>>a>>b;
		vv[a].pb(b);
		vv[b].pb(a);
	}
	dfs(1,0);
	int c1=cen(1,0),c2=c1;
	bool flag=0;
	if(n%2==0&&sz[c1]==n/2)c2=pa[c1],flag=1;
	else if(n%2==0){
		for(auto j:vv[c1])if(j!=pa[c1]&&sz[j]==n/2)c2=j,flag=1;
	}
	if(!flag){
		solve1(c1);
		return 0;
	}
	
	vt<int>v1,v2;
	dfss(c1,c2,v1);
	dfss(c2,c1,v2);
	while(v1.size()){
		ans[v1.back()]=v2.back();
		ans[v2.back()]=v1.back();
		v1.pop_back();v2.pop_back();
	}
	rp(i,n)cout<<ans[i]<<" ";
	cout<<endl;
	return 0;
}
//Crayan_r
posted @ 2023-02-19 13:57  jucason_xu  阅读(34)  评论(3编辑  收藏  举报