Atcoder Regular Contest 117 D - Miracle Tree(分析性质+构造)

Atcoder 题面传送门

笑死,阴间语文作业到现在还没写完,为了在这个点保持精神,我只好来颓篇题解辣

我们考虑探究一下怎么最小化 \(\max\limits_{i=1}^nE_i\),我们假设 \(E_{p_1}<E_{p_2}<E_{p_3}<\cdots<E_{p_n}\),那么对于 \(i\in[1,n-1]\),根据题目条件显然有 \(\text{dist}(p_i,p_{i+1})\le E_{p_{i+1}}-E_{p_i}\),累加起来则有 \(\sum\limits_{i=1}^{n-1}\text{dist}(p_i,p_{i+1})\le \sum\limits_{i=1}^{n-1}E_{p_{i+1}}-E_{p_i}=E_{p_n}-E_{p_1}\),\(E_{p_n}\) 显然就是我们要求的最大值,而 \(E_{p_1}\) 我们肯定希望它越小越好,显然我们会令 \(E_{p_1}\),也就是说最小化 \(\max\limits_{i=1}^nE_i\) 就等价于最小化 \(\sum\limits_{i=1}^{n-1}\text{dist}(p_i,p_{i+1})\),也就是最短的这是一个非常经典的问题,注意到对于一棵树而言,如果我们要求一个以 \(s\) 开头 \(s\) 为根的回路,使其长度最小,那显然一边欧拉序即可,答案即为 \(2(n-1)\),那如果不强制起点和终点相同呢?不难发现这两种情况只差一条终点 \(\to\) 起点的路径,也就是说我们要让终点 \(\to\) 起点的长度尽可能大,那显然树的直径好了,也就是说答案就是 \(2(n-1)+1\) 减树的直径的长度,这个随便乱搞即可。构造就取每个点的 \(E_i\) 为以直径的某一端点为根的 DFS 序下 \(i\) 的入栈时间,正确性证明可借鉴树上莫队,复杂度线性。

const int MAXN=2e5;
int n,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int dep1[MAXN+5],dep2[MAXN+5],rt1,rt2;
void dfs1(int x,int f){
	dep1[x]=dep1[f]+1;
	for(int e=hd[x];e;e=nxt[e]) if(to[e]^f) dfs1(to[e],x);
}
void dfs2(int x,int f){
	dep2[x]=dep2[f]+1;
	for(int e=hd[x];e;e=nxt[e]) if(to[e]^f) dfs2(to[e],x);
}
bool has[MAXN+5];int son[MAXN+5];
void dfs3(int x,int f){
	has[x]=(x==rt2);
	for(int e=hd[x];e;e=nxt[e]){
		int y=to[e];if(y==f) continue;
		dfs3(y,x);if(has[y]) has[x]=1,son[x]=y;
	}
}
int ans[MAXN+5],tim=0;
void dfs4(int x,int f){
	ans[x]=++tim;
	for(int e=hd[x];e;e=nxt[e]){
		int y=to[e];if(y==f||y==son[x]) continue;
		dfs4(y,x);tim++;
	} if(son[x]) dfs4(son[x],x),tim++;
}
int main(){
	scanf("%d",&n);
	for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
	dfs1(1,0);for(int i=1;i<=n;i++) if(dep1[i]>dep1[rt1]) rt1=i;
	dfs2(rt1,0);for(int i=1;i<=n;i++) if(dep2[i]>dep2[rt2]) rt2=i;
	dfs3(rt1,0);dfs4(rt1,0);for(int i=1;i<=n;i++) printf("%d%c",ans[i],(i==n)?'\n':' ');
	return 0;
}
上一篇:HHKB Programming Contest 2020 补题记录(D题投影,E题预处理节省时间)


下一篇:P2419 [USACO08JAN]Cow Contest S