• 题解「CF1073F Choosing Two Paths」


    有点意思又偏向套路的结论题。

    我们发现,最终答案一定是类似于一条路径 (mathrm{Path(u o v)}) 上延伸出两条路径 (mathrm{Path(x' o x),Path(y' o y)}) 这种形式,其中 (x',y') 都在路径 (u o v) 上。而我们要先让 (mathrm{dis(x',y')}) 最大(即相交部分最大),其次令路径 (mathrm{Path(u o v),Path(x' o x),Path(y' o y)}) 的长度之和最大。

    可以发现 (mathrm{Path(u o v)}) 这条路径,可以使用类似直径的两次 ( ext{dfs}) 求出。而一旦这条路径确定,另外两条路径的 (x',y') 是确定的,对应求出 (x',y') 子树中的叶子节点 (x,y) 即可。答案的链对就为 (mathrm{Path(u o v),Path(x o y)})

    但是如果 (u o v) 不满足一些条件,会导致对应求出的 (x,y) 形成的交集不是最大的,或者路径长度总和不是最大的(我在这个地方反复 ( ext{Wrong Answer on test 72/57/45}),不得不说 ( ext{Codeforces}) 的数据还是挺强的

    为了解决这个问题,我们在两遍 ( ext{dfs}) 的时候,按照优先级更新值即可。先考虑相交部分最大,其次考虑路径长度之和最大。由于需要求路径长度之和,我们需要预处理出 (x) 子树内最大距离和次大距离,这是一个套路就不细表了。

    那么,我们就可以在 (O(n)) 的时间复杂度内解决这个问题。代码写的有点凌乱随便看看就好(我才不会告诉你是我故意的呢~

    #include<cstdio>
    int pos=0,val=0,val2=0,cnt=0,mx,mn,rex,rey;
    int du[200005],h[200005],to[400005],ver[400005];
    int dis[200005],tag[200005],pre[200005],s[200005],leaf[200005],sec[200005];
    inline int read() {
    	register int x=0,f=1;register char s=getchar();
    	while(s>'9'||s<'0') {if(s=='-') f=-1;s=getchar();}
    	while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    	return x*f;
    }
    inline void swap(int &x,int &y) {int tmp=y;y=x;x=tmp;}
    inline void add(int x,int y) {to[++cnt]=y;ver[cnt]=h[x];h[x]=cnt;}
    inline void dfs2(int x) { 
    	du[x]=0;
    	if(dis[mx]-dis[mn]>val) pos=x,val=dis[mx]-dis[mn],val2=dis[leaf[mn]]+dis[leaf[mx]]+dis[x]; else if(val==dis[mx]-dis[mn]&&dis[leaf[mn]]+dis[leaf[mx]]+dis[x]>val2) pos=x,val2=dis[leaf[mn]]+dis[leaf[mx]]+dis[x];
    	for(register int i=h[x],y;i;i=ver[i]) {if(pre[x]==(y=to[i])) continue; ++du[x];}
    	for(register int i=h[x],y;i;i=ver[i]) {
    		if(pre[x]==(y=to[i])) continue; 
    		pre[y]=x; dis[y]=dis[x]+1; int premx=mx,premn=mn; 
    		int flag=0; if(leaf[y]==leaf[x]) {flag=1;swap(leaf[x],sec[x]);} 
    		if(du[x]>1) {
    			if(dis[x]>dis[mx]) mx=x;
    			else if(dis[x]==dis[mx]&&dis[leaf[x]]>dis[leaf[mx]]) mx=x;
    			if(dis[x]<dis[mn]) mn=x;
    			else if(dis[x]==dis[mn]&&dis[leaf[x]]>dis[leaf[mn]]) mn=x; 
    		} 
    		dfs2(y); mx=premx; mn=premn;
    		if(flag) swap(leaf[x],sec[x]);
    	}
    }
    inline void dfs3(int x) {
    	leaf[x]=x; 
    	for(register int i=h[x],y;i;i=ver[i]) {
    		if(pre[x]==(y=to[i])||tag[y]) continue; pre[y]=x; dfs3(y); 
    		if(dis[leaf[x]]<dis[leaf[y]]) {sec[x]=leaf[x];leaf[x]=leaf[y];}
    		else if(dis[sec[x]]<dis[leaf[y]]) {sec[x]=leaf[y];}
    	}
    }
    int main() {
    	int n=read(),top=0,st,ed; dis[0]=mx=0; dis[n+1]=mn=n+1;
    	for(register int i=1;i<n;++i) {int x=read(),y=read();add(x,y);add(y,x);}
    	dis[1]=pos=val=0; dfs2(1); st=pos; pre[st]=-1; dis[st]=pos=val=0; dfs3(st); mx=0,mn=n+1; dfs2(st); ed=pos;
    	int cur=ed,rex,rey; while(cur!=-1) {s[++top]=cur; tag[cur]=1; cur=pre[cur];} mx=0,mn=n+1;
    	for(register int i=top-1;i>=2;--i) {
    		int x=s[i];
    		for(register int k=h[x],y;k;k=ver[k]) if(!tag[y=to[k]]) mx=(dis[x]>dis[mx]? x:mx),mn=(dis[x]<dis[mn]? x:mn); 
    	}
    	dfs3(mn); rex=leaf[mn]; dfs3(mx); rey=leaf[mx];
    	printf("%d %d
    %d %d
    ",st,ed,rex,rey);
    	return 0;
    }
    
  • 相关阅读:
    Study Plan The TwentySecond Day
    Study Plan The Nineteenth Day
    Study Plan The TwentySeventh Day
    Study Plan The Twentieth Day
    Study Plan The TwentyFirst Day
    python实现进程的三种方式及其区别
    yum makecache
    JSONPath 表达式的使用
    oracle执行cmd的实现方法
    php daodb插入、更新与删除数据
  • 原文地址:https://www.cnblogs.com/tommy0103/p/13831837.html
Copyright © 2020-2023  润新知