Codeforces 1340D. Nastya and Time Machine 题解

题目连接:D. Nastya and Time Machine

题目大意:给你一棵树,通过每条边需要\(1\)的时间,你可以在一个结点处将时间变为任意一个比当前时间小的非负整数,要求满足以下两个限制:

  • 经过每个节点至少一次
  • 每一个节点上,到达它的时间(更改时的时间也计算在内)不得重复
    求出任意一种使得到达每个节点的时间最大值最小。

题解:最大最小,直接二分答案上啊。要求出一种方案,这题二分答案不大好做,考虑直接构造。

首先考虑单纯的走(即不考虑修改时间),每个节点很明显经过的次数是它的度数次,并且,如果考虑修改时间,若修改一次时间不算经过该节点一次的话,那么经过该节点的时间肯定是度数次(多了只会给自己加负担)。

那么先考虑确定下答案,二分答案多好啊(博主这个菜鸡只会二分答案了),首先,很明显最终答案肯定不小于每个点的度数中的最大值,所以答案就是每个点的度数的最大值减一(因为从\(0\)开始)……吗?样例就推翻了我们的这个结论。

仔细考虑,每个点很明显最小是它的度数减一,但是问题在于如果进入这个点时的时间不为\(0\),那么就需要更改一次时间,但是更改时间又会导致当前点时间个数的浪费,所以更改时间自然是越少越好,但因为更改时间不可避免,所以考虑每一个点能否最多只用一次更改时间,这样的话答案就是每个点的度数的最大值。

\(maxdeg=\max_{u} deg_u\text{(} deg_u\text{表示节点}u\text{的度数)}\),那么考虑让每一个点的时间取值为\([maxdeg-deg_u,maxdeg]\),一共有\(deg_u+1\)中取值,满足我们的要求。

接下来就是考虑怎么构造答案了,因为我们钦定每一个节点的时间取值是在一个范围内,所以到儿子的时间就要连续(将该区间看成一个环),因为只能更改一次时间,这可以在当前时间到达\(maxdeg\)时更改为\(maxdeg-deg_u\),然后这题就做完了(有一些简单的情况就不列了)。

下面是代码:

#include <cstdio>
void read(int &a){
	a=0;
	char c=getchar();
	while(c<'0'||c>'9'){
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		a=(a<<1)+(a<<3)+(c^48);
		c=getchar();
	}
}
int max(int a,int b){
	return a>b?a:b;
}
const int Maxn=100000;
int n,ans;
int fa[Maxn+5];
int head[Maxn+5],arrive[Maxn<<1|5],nxt[Maxn<<1|5],tot;
void add_edge(int from,int to){
	arrive[++tot]=to;
	nxt[tot]=head[from];
	head[from]=tot;
}
int deg[Maxn+5];
struct Operation{
	int u,t;
}op[Maxn<<2|5];
int len;
void work_dfs(int u,int t){
	op[++len].u=u;
	op[len].t=t;
	int last=t;
	bool flag=0;
	if(last==ans){
		last=ans-deg[u];
		flag=1;
	}
	for(int i=head[u];i;i=nxt[i]){
		int v=arrive[i];
		if(v==fa[u]){
			continue;
		}
		fa[v]=u;
		if(flag){
			op[++len].u=u;
			op[len].t=last;
			flag=0;
		}
		work_dfs(v,++last);
		op[++len].u=u;
		op[len].t=last;
		if(last==ans){
			last=ans-deg[u];
			flag=1;
		}
	}
	if(flag){
		last=ans;
	}
	if(u!=1&&last!=t-1){
		op[++len].u=u;
		op[len].t=t-1;
	}
}
int main(){
	read(n);
	for(int i=1;i<n;i++){
		int u,v;
		read(u),read(v);
		add_edge(u,v);
		add_edge(v,u);
		deg[u]++,deg[v]++;
	}
	for(int i=1;i<=n;i++){
		ans=max(ans,deg[i]);
	}
	work_dfs(1,0);
	printf("%d\n",len);
	for(int i=1;i<=len;i++){
		printf("%d %d\n",op[i].u,op[i].t);
	}
	return 0;
}
posted @ 2020-04-27 21:24  with_hope  阅读(337)  评论(0编辑  收藏  举报