2021-2022年度國際大學生程序設計競賽第10屆陝西省程序設計競賽(正式賽)A-Tree

官方題解:https://blog.csdn.net/qq_62464995/article/details/127493921

題目大意

給出一棵邊權爲1的樹,構造排列p,使得

①p[1]=1
②dis(p[i],p[i+1])<=k

題解

神必防ak題


當k=1時,顯然只能是從1開始的一條鏈

當k>=3時,一定有解,考慮構造:
把樹上的點按層黑白黑白染色,dfs遍歷整棵樹,在第一次進入黑點第一次走出白點時把點加入p中

最後是1-4-5-2-6-7-3

當k=2時,考慮dp:
設f[i]表示走一步走進i,能否走完i的子樹
設g[i]表示從i的父親跳到i的兒子,能否走完i子樹之後走回i
設h[i]表示從i的父親跳到i的兒子,能否走完i的子樹


先不考慮h,考慮f和g的轉移
給一個點i的兒子分類,size=1的兒子稱爲散點,記作x;size>1的兒子才用f/g/h的走法來走,則

f的轉移:i(g)xx(f)
g的轉移:xx(g')i(g'表示把路徑g反轉,即從i走完子樹後跳到父親

(i是當前的根)

發現這樣還是不充要,比如下面這一組

20 2
1 2 2 4 4 6 5 5 9 5 7 11 13 3 4 6 4 16 9 

那麼此時引入h[i],f的轉移多了一條 h(一個兒子,這個兒子走h)
h的轉移:xxih / xxg'ih / xxg'igf
(爲了方便處理,能走一步到i再走f解決的就不在h裏處理,比如gxxf,就可以走一步到i再走f[i],沒必要處理)
(h實際就是先跳進去走g,回到根i之後在另一邊走f)


構造方案的話就用雙向鏈表,記錄兩個方向分別到哪裏
注意多次反轉+合併之後next[0/1]對應的前/後關係會混亂,所以遍歷需要用pre和now一步步走,
同時兩條鏈的合併需要用next[]爲空的進行連邊;反轉直接改變direction,這樣就可以O(1)反轉+合併,最後O(n)遍歷

code

//#include <bits/stdc++.h>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
//#define file
using namespace std;

class Node{
	public:
		Node* nx[2];
		int val=0;
		
		Node() {nx[0]=nx[1]=nullptr;}
		Node(int v) {nx[0]=nx[1]=nullptr;val=v;}
};
Node* NextNode(int pre,Node* &Now)
{
	int i;
	fo(i,0,1)
	if (Now->nx[i]!=nullptr && (Now->nx[i])->val==pre)
	return Now->nx[i^1];
	
	fo(i,0,1)
	if (Now->nx[i]!=nullptr)
	return Now->nx[i];
	
	return nullptr;
}

class List{
	public:
		int dir=0;
		Node* head[2];
		
		List()
		{
			dir=0;
			head[0]=head[1]=nullptr;
		}
		List(int val)
		{
			dir=0;
			head[0]=new Node(val);
			head[1]=head[0];
		}
		
		void linkNode(Node* x,Node* y)
		{
			int i;
			fo(i,0,1)
			if (x->nx[i]==nullptr)
			{
				x->nx[i]=y;
				return;
			}
		}
		
		void link(List& another)
		{
			linkNode(head[dir^1],another.head[another.dir]);
			linkNode(another.head[another.dir],head[dir^1]);
			head[dir^1]=another.head[another.dir^1];
		}
		
		void Reverse()
		{
			dir^=1;
		}
};

int n,K,i,j,k,l,x,y,z;
int a[400001][2],ls[200001],len;
bool f[200001],g[200001],h[200001]; //g ok=>f ok
int Size[200001];
vector<int> ans;
List ans2[200001];

int dis[101][101];
void checker()
{
	if (n<=100)
	{
		fo(k,1,n)
		{
			fo(i,1,n)
			if (i!=k)
			{
				fo(j,1,n)
				if (j!=i && j!=k)
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
			}
		}
		
		fo(i,1,n-1)
		if (dis[ans[i]][ans[i+1]]>K)
		{
			cout<<"Oh shit"<<endl;
			exit(0);
		}
	}
}

void Exit()
{
	printf("No\n");
	exit(0);
}

void New(int x,int y)
{
	++len;
	a[len][0]=y;
	a[len][1]=ls[x];
	ls[x]=len;
}

void dfsk3(int Fa,int t,int dep)
{
	int i;
	if (dep==1) ans.push_back(t);
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	dfsk3(t,a[i][0],dep^1);
	
	if (dep==0) ans.push_back(t);
}

void dfs(int Fa,int t)
{
	int i;
	Size[t]=1;
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	{
		dfs(t,a[i][0]);
		Size[t]+=Size[a[i][0]];
	}
}
void dfs_dp(int Fa,int t)
{
	int i,id1=0,id2=0,id3=0;
	vector<int> sandian;
	sandian.clear();
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	{
		if (Size[a[i][0]]==1)
		sandian.push_back(a[i][0]);
		else
		{
			if (!id1)
			id1=a[i][0];
			else
			if (!id2)
			id2=a[i][0];
			else
			if (!id3)
			id3=a[i][0];
			else
			Exit();
		}
	}
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	dfs_dp(t,a[i][0]);
	
	if (t==2)
	n=n;
	
//	f:
	if (!id1) f[t]=1;
	else
	if (sandian.size()==0 && h[id1]) //h
	f[t]=1;
	else
	if (!id2)
	{
		if (f[id1] || g[id1]) //xxf or gxx
		f[t]=1;
	}
	else
	if (!id3)
	{
		if (f[id1] && g[id2] || f[id2] && g[id1]) //gxxf
		f[t]=1;
	}
	else
	f[t]=0;
	
//	g:
	if (!id1 && sandian.size()>0) g[t]=1;
	else
	if (!id2)
	{
		if (g[id1]) //xxg'
		g[t]=1;
	}
	else
	g[t]=0;
	
//	h: xxh or xxg'hxx or xxg'gf
	
	if (!id1)
	h[t]=0;
	else
	if (!id2)
	{
		if (sandian.size()>0 && h[id1])
		h[t]=1;
	}
	if (!id3)
	{
		if (g[id1] && h[id2] || g[id2] && h[id1])
		h[t]=1;
	}
	else
	{
		if (f[id1] && g[id2] && g[id3] || f[id2] && g[id1] && g[id3] || f[id3] && g[id2] && g[id1])
		h[t]=1;
	}
}

void dfs_con(int Fa,int t,int tp) //tp=0f/1g/2h
{
	int i,id1=0,id2=0,id3=0,sz;
	vector<int> sandian;
	sandian.clear();
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	{
		if (Size[a[i][0]]==1)
		sandian.push_back(a[i][0]);
		else
		{
			if (!id1)
			id1=a[i][0];
			else
			if (!id2)
			id2=a[i][0];
			else
			if (!id3)
			id3=a[i][0];
			else
			Exit();
		}
	}
	sz=sandian.size();
	
	if (tp==0) //	f:
	{
		if (!id1) //xxx
		{
			fo(i,0,sz-1)
			ans2[t].link(ans2[sandian[i]]);
		}
		else
		if (sandian.size()==0 && h[id1]) //h
		{
			dfs_con(t,id1,2);
			
			ans2[t].link(ans2[id1]);
		}
		else
		if (!id2)
		{
			if (f[id1]) //xxf
			{
				dfs_con(t,id1,0);
				
				fo(i,0,sz-1)
				ans2[t].link(ans2[sandian[i]]);
				ans2[t].link(ans2[id1]);
			}
			else //gxx
			{
				dfs_con(t,id1,1);
				
				ans2[t].link(ans2[id1]);
				fo(i,0,sz-1)
				ans2[t].link(ans2[sandian[i]]);
			}
		}
		else //gxxf
		{
			if (f[id2] && g[id1]) swap(id1,id2);
			dfs_con(t,id1,0);
			dfs_con(t,id2,1);
			
			ans2[t].link(ans2[id2]);
			fo(i,0,sz-1)
			ans2[t].link(ans2[sandian[i]]);
			ans2[t].link(ans2[id1]);
		}
	}
	else //	g:
	if (tp==1)
	{
		if (!id1 && sandian.size()>0) //xxxt
		{
			fo(i,0,sz-1)
			ans2[t].link(ans2[sandian[i]]);
			ans2[t].Reverse();
		}
		else
		if (!id2) //xxg't=(tgxx)'
		{
			dfs_con(t,id1,1);
			
			ans2[t].link(ans2[id1]);
			fo(i,0,sz-1)
			ans2[t].link(ans2[sandian[i]]);
			ans2[t].Reverse();
		}
		else
		g[t]=0;
	}
	else
	if (tp==2) //h
	{
		if (!id1)
		h[t]=0; //can't
		else
		if (!id2)
		{
			if (sandian.size()>0 && h[id1]) //xxth=(txx)'h
			{
				dfs_con(t,id1,2);
				
				fo(i,0,sz-1)
				ans2[t].link(ans2[sandian[i]]); //xx
				ans2[t].Reverse(); //(txx)'h
				ans2[t].link(ans2[id1]);
			}
		}
		else
		if (!id3) //xxg'th
		{
			if (g[id2] && h[id1]) swap(id1,id2);
//			if (g[id1] && h[id2] || g[id2] && h[id1])
			dfs_con(t,id1,1);
			dfs_con(t,id2,2);
			
			ans2[t].link(ans2[id1]); //g
			fo(i,0,sz-1)
			ans2[t].link(ans2[sandian[i]]); //xx
			ans2[t].Reverse(); //tgxx => xxg't
			ans2[t].link(ans2[id2]); //h
		}
		else //xxg'tgf
		{
			if (f[id2] && g[id1] && g[id3]) swap(id1,id2);
			else
			if (f[id3] && g[id1] && g[id2]) swap(id1,id3);
//			if (f[id1] && g[id2] && g[id3] || f[id2] && g[id1] && g[id3] || f[id3] && g[id2] && g[id1])
			dfs_con(t,id1,0);
			dfs_con(t,id2,1);
			dfs_con(t,id3,1);
			
			ans2[t].link(ans2[id2]); //g1
			fo(i,0,sz-1)
			ans2[t].link(ans2[sandian[i]]); //xx
			ans2[t].Reverse(); //tgxx => xxg't
			ans2[t].link(ans2[id3]); //g2
			ans2[t].link(ans2[id1]); //f
		}
	}
}

int main()
{
	#ifdef file
	freopen("A.in","r",stdin);
	freopen("A.out","w",stdout);
	#endif
	
	ans.push_back(0);
	
	memset(dis,1,sizeof(dis));
	scanf("%d%d",&n,&K);
	fo(i,2,n)
	{
		scanf("%d",&x),New(x,i),New(i,x);
		if (n<=100)
		dis[x][i]=dis[i][x]=1;
	}
	
	if (K==1)
	{
		x=1,l=0;
		while (1)
		{
			bool find=0;
			ans.push_back(x);
			
			for (i=ls[x]; i; i=a[i][1])
			if (a[i][0]!=l)
			{
				l=x;x=a[i][0];
				find=1;
				break;
			}
			if (!find) break;
		}
		if (ans.size()!=n+1) {printf("No\n");return 0;}
	}
	else
	if (K>=3)
	{
		dfsk3(0,1,1);
	}
	else
	{
		fo(i,1,n) ans2[i]=List(i);
		
		dfs(0,1);
		dfs_dp(0,1);
		
		if (f[1])
		{
			dfs_con(0,1,0);
			
			Node* Now=ans2[1].head[ans2[1].dir];
			l=0,x=1;
			while (Now!=nullptr)
			{
				x=Now->val;
				ans.push_back(x);
				Now=NextNode(l,Now),l=x;
			}
		}
		else
		Exit();
	}
	
	if (ans.size()!=n+1) Exit();
	checker();
	
	printf("Yes\n");
	printf("%d",ans[1]);fo(i,2,n) printf(" %d",ans[i]);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
//20 2
//1 2 2 4 4 6 5 5 9 5 7 11 13 3 4 6 4 16 9 
//Yes
//20 2
//1 2 2 2 1 3 4 6 3 6 2 5 11 8 8 15 11 13 17 
//No
//12 2
//1 2 3 3 5 3 7 3 4 2 4 
//Yes
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章