思路是把三度及以上点视为特殊点,求虚树直径,对于虚树的每个直径的两个端点延伸最长,这个长度需要维护原树的最大值,次大值,第三大值。
求虚树直径用的dp,求的最大值和次大值。
(码风毒瘤,但比较模块化)
// Problem: CF1073F Choosing Two Paths
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1073F
// Memory Limit: 250 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
#define F(i,a,b) for(int i=a,i##end=b;i<=i##end;i++)
#define G(i,x) for(int i=start[x];i;i=Next[i])
using namespace std;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char *p1,*p2,buf[1<<21];
int read() {
int s=0,w=0;char ch=getchar();
while(ch<'0'||ch>'9') w|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return w?-s:s;
}
const int N=2e5+5,M=N<<1;
int n,cnt,v[M],Next[M],start[N],tot,dfn[N],dfx[N],dep[N],st[N][20],k,V[N];
int o1,q1,o2,q2;
struct LIAN {
int l,x;
bool operator<(LIAN b)const{return l<b.l;}
bool operator>(LIAN b)const{return l>b.l;}
LIAN operator+(int b)const{return {l+b,x};}
} h[N],ma[N][4],a1,a2;
void add(int x,int y) {v[++cnt]=y;Next[cnt]=start[x];start[x]=cnt;}
void Add(int x,int y) {add(x,y);add(y,x);}
void geng(int x,LIAN p) {
if(p>ma[x][1]) swap(ma[x][1],p);
if(p>ma[x][2]) swap(ma[x][2],p);
if(p>ma[x][3]) swap(ma[x][3],p);
}
void d1(int x,int fa) {
dfn[x]=++tot;dfx[tot]=x;dep[x]=dep[fa]+1;st[dfn[x]][0]=fa;
ma[x][1]=ma[x][2]=ma[x][3]=h[x]={0,x};
G(i,x) if(v[i]^fa) {
d1(v[i],x);
geng(x,ma[v[i]][1]+1);
}
}
void d2(int x,int fa) {
G(i,x) if(v[i]^fa) {
h[v[i]]=max(h[x],ma[v[i]][1].l+1==ma[x][1].l?ma[x][2]:ma[x][1])+1;
d2(v[i],x);
} geng(x,h[x]);
}
int Min(int x,int y) {return dep[x]<dep[y]?x:y;}
int lca(int x,int y) {
if(x==y) return x;
x=dfn[x];y=dfn[y];
if(x>y) swap(x,y);
x++;int p=__lg(y-x+1);
return Min(st[x][p],st[y-(1<<p)+1][p]);
}
int dis(int x,int y) {return dep[x]+dep[y]-2*dep[lca(x,y)];}
bool in(int x,int a,int b) {return dis(a,x)+dis(b,x)==dis(a,b);}
int wai(LIAN &a,LIAN &b) {
int ansa,ansb;
if(in(a.x,b.x,ma[b.x][1].x)) ansb=ma[b.x][2].l+ma[b.x][3].l;
else if(in(a.x,b.x,ma[b.x][2].x)) ansb=ma[b.x][1].l+ma[b.x][3].l;
else ansb=ma[b.x][1].l+ma[b.x][2].l;
if(in(b.x,a.x,ma[a.x][1].x)) ansa=ma[a.x][2].l+ma[a.x][3].l;
else if(in(b.x,a.x,ma[a.x][2].x)) ansa=ma[a.x][1].l+ma[a.x][3].l;
else ansa=ma[a.x][1].l+ma[a.x][2].l;
return ansa+ansb;
}
void upd(LIAN &a,LIAN &b) {
if(a.l+b.l>a1.l+a2.l) a1=a,a2=b;
else if(a.l+b.l==a1.l+a2.l&&wai(a,b)>wai(a1,a2)) a1=a,a2=b;
}
struct XU {
int cnt,v[M],w[M],Next[M],start[N];
LIAN f[N],g[N];
void add(int x,int y,int z) {v[++cnt]=y;w[cnt]=z;Next[cnt]=start[x];start[x]=cnt;}
void Add(int x,int y,int z) {add(x,y,z);add(y,x,z);}
void Add(int x,int y) {Add(x,y,dep[y]-dep[x]);}
void d1(int x,int fa) {
f[x]=g[x]={0,x};
G(i,x) if(v[i]^fa) {
d1(v[i],x);
auto t=f[v[i]]+w[i];
if(t>f[x]) swap(t,f[x]);
if(t>g[x]) swap(t,g[x]);
} if(f[x].l+g[x].l>=a1.l+a2.l) upd(f[x],g[x]);
}
} xu;
int main() {
n=read();
F(i,1,n-1) Add(read(),read());d1(1,0);d2(1,0);
F(j,1,19) F(i,1,n) if(i+(1<<j-1)<=n) st[i][j]=Min(st[i][j-1],st[i+(1<<j-1)][j-1]);
F(i,1,n) if(Next[Next[start[i]]]) V[++k]=i;
sort(V+1,V+k+1,[](int x,int y){return dfn[x]<dfn[y];});
F(i,1,k-1) V[++k]=lca(V[i],V[i+1]);
sort(V+1,V+k+1,[](int x,int y){return dfn[x]<dfn[y];});
k=unique(V+1,V+k+1)-V-1;
F(i,1,k-1) xu.Add(lca(V[i],V[i+1]),V[i+1]);xu.d1(V[1],0);
if(in(a1.x,a2.x,ma[a2.x][1].x)) o1=ma[a2.x][2].x,o2=ma[a2.x][3].x;
else if(in(a1.x,a2.x,ma[a2.x][2].x)) o1=ma[a2.x][1].x,o2=ma[a2.x][3].x;
else o1=ma[a2.x][1].x,o2=ma[a2.x][2].x;
if(in(a2.x,a1.x,ma[a1.x][1].x)) q1=ma[a1.x][2].x,q2=ma[a1.x][3].x;
else if(in(a2.x,a1.x,ma[a1.x][2].x)) q1=ma[a1.x][1].x,q2=ma[a1.x][3].x;
else q1=ma[a1.x][1].x,q2=ma[a1.x][2].x;
cout<<o1<<' '<<q1<<endl<<o2<<' '<<q2<<endl;
// cerr<<"PP\n";
// cerr<<a1.x<<' '<<q1<<' '<<q2<<endl;
// cerr<<a2.x<<' '<<o1<<' '<<o2<<endl;
// cerr<<"LANS"<<wai(a1,a2)<<endl;
return 0;
}
Wrong answer on test 6
Output:
148779 13235
79398 174858
Answer:
13235 79398
174858 75754
Checker Log:
wrong answer The number of common vertices in the jury answer is greater than in the participant answer