【CSP-S2019D1T3】树上的数

Description

在这里插入图片描述
在这里插入图片描述

Solution

瞎扯

  • 你管这叫联赛????NOIplus,CSP SCP Summer Camp Plus妙啊
  • 考场上想了两个小时,想出来了链和菊花,但是因为链比较难打,所以只打了菊花。。。没有时间打链了,难受。
  • 然而出来之后发现各路集训队dalao都没有调出来??同年级的也没有几个打菊花的??不亏。
  • 并且这个输入反了过来,除了方便标程以外就是反人类的操作。
  • 链的比较复杂,这里就不说了。而菊花的手玩一下会发现最终会变成将n个点连成一个环,顺位移动,用一个链表和并查集维护一波。

正解

  • 正解与这个做法有一点相似,但是却需要转换选择这些边的限制。
  • 首先肯定是贪心考虑每一个数字最终所在的编号,要使它最小并且不与之前矛盾,并且保证最后有至少一种方案。
  • 对于一个点的所有边肯定有一种选择的顺序,考虑从这里下手。
  • 那么对于一条路径要把x的数字移到y,在x到y的路径上,x的出边必须第一个选,y的入边必须最后一个选,经过一个z点,入边必须在出边的前一个选。这就是一个链表的模型。
  • 因为只要满足这个条件剩下的边可以随便选,所以这就成为了充分必要条件,并且每一个点的所有连边顺序是互相独立的。
  • 那么对于每一次贪心,用一个链表+并查集维护一波就好了。

细节

  • 思想如果顺着正解的话这题不失为一道NOIP的好题,为什么众多集训队dalao在怒刚3h后惨痛爆炸呢?这究竟是人性的扭曲还是道德的沦丧?
  • 实际上有很多的细节。
  • 例如在确定一些相邻的边的顺序之后,开头和结尾就可能已经确定了,这个要实时更新,或者开头结尾确定,中间有一些限制也就可以限制了,并且如果在某个时刻开头和结尾连在了一起,要保证所有的边都已经夹在他们之间了。
  • 而且在某个限制要被安排之前,可能已经刚好安排了这个限制。
  • 实际上想清楚就没有问题了,但是刚开始忽略了很多地方的以上的判断,所以删删改改调了好久。
  • 怒敲3k
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 2005
#define mem(a) memset(a,0,sizeof(a))
using namespace std;

int T,n,i,j,k,x,y,mi,a[maxn],pre[maxn*2],nex[maxn*2];
int em,e[maxn*2],nx[maxn*2],ls[maxn*2],cnt[maxn];
int st[maxn],ed[maxn];

int fa[maxn*2];
int father(int x){return (fa[x]==x)?x:fa[x]=father(fa[x]);}

void read(int &x){
	x=0; char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
}

void insert(int x,int y){
	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em; fa[em]=em; cnt[x]++;
	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em; fa[em]=em; cnt[y]++;
}

void DFS(int x,int p){
	if (ed[x]==p||(!ed[x]&&!nex[p]&&(!st[x]||father(p)!=father(st[x])))){
		mi=min(mi,x);
	}
	for(int i=ls[x];i;i=nx[i]) if (father(i)!=father(p)||nex[p]==i){
		if ((!pre[i]||pre[i]==p)&&(!nex[p]||nex[p]==i)&&ed[x]!=p&&st[x]!=i){ 
			if (st[x]&&father(st[x])==father(p)&&ed[x]&&father(ed[x])==father(i) && cnt[x]>1) 
				continue;
				
			DFS(e[i],i^1);
		}
	}
}

void link(int x,int y){
	x=father(x),y=father(y);
	if (x!=y) fa[x]=y;
}

void upd(int x){
	if (cnt[x]==1){
		if (st[x]&&!ed[x]){
			int now,nexi,las;
			for(int i=ls[x];i;i=nx[i]) if (i!=st[x]&&!pre[i]) nexi=i;
			for(now=st[x];nex[now];now=nex[now]);
			for(las=nexi;nex[las];las=nex[las]);
			nex[now]=nexi,pre[nexi]=now,ed[x]=las;
			link(now,nexi);
		} else
		if (!st[x]&&ed[x]){
			int now,nexi,las;
			for(int i=ls[x];i;i=nx[i]) if (i!=ed[x]&&!nex[i]) nexi=i;
			for(now=ed[x];pre[now];now=pre[now]);
			for(las=nexi;pre[las];las=pre[las]);
			pre[now]=nexi,nex[nexi]=now,st[x]=las;
			link(now,nexi);
		} else
		if (st[x]&&ed[x]){
			int fir,las;
			for(int i=ls[x];i;i=nx[i]) if (!pre[i]&&i!=st[x]) las=i;
			else if (!nex[i]&&i!=ed[x]) fir=i;
			pre[las]=fir,nex[fir]=las;
			link(las,fir);
		} else cnt[x]++;
		cnt[x]--;
	} else 
	if (cnt[x]==0&&(!st[x]||!ed[x])){
		int fir,las;
		for(int i=ls[x];i;i=nx[i]) {
			if (!pre[i]) fir=i;
			if (!nex[i]) las=i;
		}
		st[x]=fir,ed[x]=las;
	}	
}

int Cover(int x,int p){
	if (x==mi) {
		ed[x]=p;
		upd(x);
		return 1;
	}
	for(int i=ls[x];i;i=nx[i]) if (i!=p){
		if (Cover(e[i],i^1)){
			if (!p) st[x]=i; else {
				nex[p]=i,pre[i]=p,cnt[x]--;
				link(i,p);
			}
			upd(x);
			return 1;
		}
	}
	return 0;
}

int main(){
	freopen("ceshi.in","r",stdin);
//	freopen("tree.in","r",stdin);
//	freopen("tree.out","w",stdout);
	read(T);
	while (T--){
		read(n);
		em=1,mem(ls),mem(pre),mem(nex),mem(st),mem(ed),mem(cnt);
		for(i=1;i<=n;i++) read(a[i]);
		for(i=1;i<n;i++) read(x),read(y),insert(x,y);
		for(i=1;i<=n;i++) cnt[i]--;
		for(i=1;i<=n;i++){
			x=a[i]; mi=n+1;
			if (st[x]) DFS(e[st[x]],st[x]^1); else 
			for(j=ls[x];j;j=nx[j]) if (!pre[j]&&(!ed[x]||father(j)!=father(ed[x])))
				DFS(e[j],j^1);
			Cover(x,0);
			printf("%d ",mi);
		}
		printf("
");
	}
}

原文地址:https://www.cnblogs.com/DeepThinking/p/13090907.html