首页 > 编程语言 >2021-2022年度国际大学生程序设计竞赛第10届陕西省程序设计竞赛(正式赛)A-Tree

2021-2022年度国际大学生程序设计竞赛第10届陕西省程序设计竞赛(正式赛)A-Tree

时间:2023-05-08 12:11:45浏览次数:69  
标签:10 竞赛 sandian ans2 id2 id1 && 程序设计 else

官方题解: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

标签:10,竞赛,sandian,ans2,id2,id1,&&,程序设计,else
From: https://www.cnblogs.com/gmh77/p/17381335.html

相关文章

  • 【面向对象依赖关系概念总结】面向对象程序设计的五种依赖关系
    ​目录 简介继承关系聚合关系组合关系关联关系依赖关系总结 简介        面向对象程序设计中,要实现复杂的模块化系统,需要将系统划分为多个对象并组织它们之间的关系,这就涉及到常说的面向对象五大依赖关系。这五种依赖关系分别是:继承、聚合、组合、关联和依......
  • vs2010单元测试
    一、     实验目的1、 掌握单元测试技术,并按单元测试的要求设计测试用例。 2、 掌握一种单元测试工具的使用。二、 实验内容自行学习vs2010或vs2012或vs2015等单元测试工具的使用。对下面被测代码进行测试且查看代码覆盖率,并录制操作视频,撰写实验报告。三、 设......
  • 爬虫 202107【JavaPub版】
    写于2021071117:10北京朝阳区@[toc]方法:首先下载mitproxy,pip安装方法:>pipinstallmitmproxy基本使用方法:给本机设置代理ip127.0.0.1端口8001(为了让所有流量走mitmproxy)具体方法请百度。启动mitmproxy。windows:>mitmdump-p8001Linux:>mitmproxy-p80012.修改chromedriver......
  • 【JVM】10道不得不会的JVM面试题
    我是JavaPub,专注于面试、副业,技术人的成长记录。以下是JVM面试题,相信大家都会有种及眼熟又陌生的感觉、看过可能在短暂的面试后又马上忘记了。JavaPub在这里整理这些容易忘记的重点知识及解答,建议收藏,经常温习查阅。评论区见@[toc]JVM基于JDK81.说一说JVM的主要组成部分点击放大......
  • 【ElasticSearch面试】10道不得不会的ElasticSearch面试题
    以下是ElasticSearch面试题,相信大家都会有种及眼熟又陌生的感觉、看过可能在短暂的面试后又马上忘记了。JavaPub在这里整理这些容易忘记的重点知识及解答,建议收藏,经常温习查阅。评论区见关于es的面试,建议使用名词用官方语言描述会更准确。@[toc]1.说说你们公司es的集群架构,索......
  • [ERROR] [MY-010020] [Server] Data Dictionary initialization failed
     死活看这个报错,查看mysql数据目录权限,发现初始化命令敲错了, ......
  • Win10打开IE自动跳转至Edge解决办法
    WIN+R输入inetcpl.cpl弹出Internet属性对话窗口点击上面菜单中的【高级】选项滑动右侧滚动条,找到【浏览】项下面的【启用第三方浏览器拓展*】并取消勾选双击IE浏览器图标测试是否生效......
  • GYM103743H Super Gray Pony - 思维 -
    题目链接:https://codeforces.com/gym/103743/problem/H这应该是近期做出来的最难的题之一了……想了一个多小时首先,如何由\(S\)求得$a^{(n)}(S)$?考虑\(S\)的每一位0/1如果第一位是1,那么相当于就知道了剩下的数字在\(rev(a^{(n-1)})\)(即在右侧)中,此时如果第二位为0,......
  • C#基础10 有关字符串,枚举内容
    字符串      重点掌握字符串特点 错误提示    -----Length:显示长度    ------Equals():比较两个属性是否内容相等  ----- Contains()|Replace():判断给定的字符是否出现过,如果有就用replace替代字符------Trim()|TrimStart()|TrimEends():去空......
  • 第10章:10W QPS真刀实操__以及基于ZK+Netty手写分布式测试工具 177手机路人甲账号 主目
    10WQPS真刀实操__以及基于ZK+Netty手写分布式测试工具参考链接系统架构知识图谱(一张价值10w的系统架构知识图谱)https://www.processon.com/view/link/60fb9421637689719d246739秒杀系统的架构https://www.processon.com/view/link/61148c2b1e08536191d8f92f10WQPS真刀实......