題目描述
Description
2214年“Russian Code Cup”的最終決賽將在n 座賓館裏舉行。其中的兩座賓館(讓我們稱它們爲主賓館)將要主辦所有的活動,並且剩下的賓館將會容納所有參賽者。這些賓館被總共n-1 條道路連接,使得你能從任一座賓館到達另外任意一座。
組委會想要知道,如果通過一條連接兩座賓館的道路耗費一單位時間,並且每個參賽者的目的地是距離他們自己最近的主賓館之一;那麼,所有參賽者同時出發,最後所有人均到達目的地的最少所需時間爲多少。
委員在研究很多種主賓館分佈的方案。對於每種方案,幫助委員會找到最少所需時間。
Input
第一行包含一個整數n(2 <= n <= 100000)——賓館的數量。接下來n-1行每行包含兩個整數——每條路連接的兩座賓館。可以認爲,賓館從1 到n 編號。
接下來的一行包含一個整數m(1<= m <= 100000)——詢問的數量。接下來m 行每行包含兩個不相同的整數——我們假設爲主賓館的賓館編號。
Output
對於每個組委會的請求輸出單獨一個整數——所有參賽者都到達主賓館所需時間。
Sample Input
輸入1:
3
2 3
3 1
3
2 1
2 3
3 1
輸入2:
4
1 4
1 2
2 3
3
1 4
1 3
2 3
Sample Output
輸出1:
1
1
1
輸出2:
2
1
2
Data Constraint
對於30% 的數據,n,m <=1000。
題解
碼農題(1/3)
一種簡單(?)的方法是用LCT維護最大深度,然後貌似要用set。。。
還有一種更簡單(?)的方法
考慮倍增維護
先欽定x的深度小於y的深度
那麼x–y的中點一定在x–lca這一段
①y是x的祖先
那麼可以分成如下幾部分計算:
①x的子樹到x+②x~mid上的子樹到x+③mid~y上的子樹到y+④y的祖先的其它子樹到y
②xy沒有祖先關係
答案:①x的子樹到x+②y的子樹到y+③x~mid上的子樹到x+④mid~lca到y+⑤y~lca到y+⑥lca的祖先的子樹到y+⑦lca除x和y所在子樹到y
其中①②⑥可以dp,③④⑤倍增維護,⑦維護每個子樹中前三大
清真
code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
using namespace std;
int a[200001][2];
int ls[100001];
int f[100001];
int g[100001];
int g1[100001][17];
int g2[100001][17];
int G[100001][6];
int fa[100001][17];
int d[100001];
int n,Q,i,j,k,l,len,x,y,Lca,ans,s,S,X,Y;
void New(int x,int y)
{
++len;
a[len][0]=y;
a[len][1]=ls[x];
ls[x]=len;
}
void dfs(int Fa,int t)
{
int i;
d[t]=d[Fa]+1;
fa[t][0]=Fa;
fo(i,1,16)
fa[t][i]=fa[fa[t][i-1]][i-1];
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
{
dfs(t,a[i][0]);
f[t]=max(f[t],f[a[i][0]]+1);
}
}
void Dfs(int Fa,int t)
{
int i,mx1=0,Mx1=0,mx2=0,Mx2=0;
if (Fa)
g[t]=max(g[t],g[Fa]+1);
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
{
if (f[a[i][0]]+2>mx1)
{
mx2=mx1;
Mx2=Mx1;
mx1=f[a[i][0]]+2;
Mx1=a[i][0];
}
else
if (f[a[i][0]]+2>mx2)
{
mx2=f[a[i][0]]+2;
Mx2=a[i][0];
}
if (f[a[i][0]]+1>G[t][0] || f[a[i][0]]+1==G[t][0] && a[i][0]<G[t][1])
{
G[t][4]=G[t][2];
G[t][5]=G[t][3];
G[t][2]=G[t][0];
G[t][3]=G[t][1];
G[t][0]=f[a[i][0]]+1;
G[t][1]=a[i][0];
}
else
if (f[a[i][0]]+1>G[t][2] || f[a[i][0]]+1==G[t][2] && a[i][0]<G[t][3])
{
G[t][4]=G[t][2];
G[t][5]=G[t][3];
G[t][2]=f[a[i][0]]+1;
G[t][3]=a[i][0];
}
else
if (f[a[i][0]]+1>G[t][4] || f[a[i][0]]+1==G[t][4] && a[i][0]<G[t][5])
{
G[t][4]=f[a[i][0]]+1;
G[t][5]=a[i][0];
}
}
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
{
if (a[i][0]==Mx1)
{
g[a[i][0]]=mx2;
Dfs(t,a[i][0]);
}
else
{
g[a[i][0]]=mx1;
Dfs(t,a[i][0]);
}
}
}
void DFS(int Fa,int t)
{
int i,mx1=-2133333333,Mx1=0,mx2=-2133333333,Mx2=0;
fo(i,1,16)
{
g1[t][i]=max(g1[t][i-1],g1[fa[t][i-1]][i-1]);
g2[t][i]=max(g2[t][i-1],g2[fa[t][i-1]][i-1]);
}
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
{
if (f[a[i][0]]+1>mx1)
{
mx2=mx1;
Mx2=Mx1;
mx1=f[a[i][0]]+1;
Mx1=a[i][0];
}
else
if (f[a[i][0]]+1>mx2)
{
mx2=f[a[i][0]]+1;
Mx2=a[i][0];
}
}
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
{
if (a[i][0]==Mx1)
{
g1[a[i][0]][0]=mx2-d[t];
g2[a[i][0]][0]=mx2+d[t];
DFS(t,a[i][0]);
}
else
{
g1[a[i][0]][0]=mx1-d[t];
g2[a[i][0]][0]=mx1+d[t];
DFS(t,a[i][0]);
}
}
}
int lca(int x,int y)
{
int i;
if (d[x]<d[y])
swap(x,y);
fd(i,16,0)
if (d[fa[x][i]]>=d[y])
x=fa[x][i];
fd(i,16,0)
if (fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
if (x!=y)
x=fa[x][0];
return x;
}
int jump(int t,int s)
{
int i;
i=0;
while (s)
{
if (s&1)
t=fa[t][i];
s>>=1;
++i;
}
return t;
}
int find1(int t,int s)
{
int ans=-2133333333;
int i;
i=0;
while (s)
{
if (s&1)
{
ans=max(ans,g1[t][i]);
t=fa[t][i];
}
s>>=1;
++i;
}
return ans;
}
int find2(int t,int s)
{
int ans=-2133333333;
int i;
i=0;
while (s)
{
if (s&1)
{
ans=max(ans,g2[t][i]);
t=fa[t][i];
}
s>>=1;
++i;
}
return ans;
}
int main()
{
// freopen("S8_10_1.in","r",stdin);
// freopen("a.in","r",stdin);
// freopen("b.out","w",stdout);
memset(g1,128,sizeof(g1));
memset(g2,128,sizeof(g2));
scanf("%d",&n);
fo(i,2,n)
{
scanf("%d%d",&j,&k);
New(j,k);
New(k,j);
}
dfs(0,1);
Dfs(0,1);
DFS(0,1);
scanf("%d",&Q);
for (;Q;--Q)
{
scanf("%d%d",&x,&y);
if (d[x]<d[y])
swap(x,y);
X=x;
Y=y;
Lca=lca(x,y);
if (Lca==y)
{
s=d[x]-d[y];
ans=max(max(f[x],g[y]),s/2);
S=d[x]+find1(x,s/2);
ans=max(ans,S);
x=jump(x,s/2);
S=find2(x,(s+1)/2)-d[y];
ans=max(ans,S);
}
else
{
s=d[x]+d[y]-d[Lca]-d[Lca];
ans=max(max(max(f[x],f[y]),g[Lca]+d[y]-d[Lca]),s/2);
if (d[x]-s/2-d[Lca]>=1)
{
S=d[x]+find1(x,s/2);
ans=max(ans,S);
x=jump(x,s/2);
}
else
{
S=d[x]+find1(x,d[x]-d[Lca]-1);
ans=max(ans,S);
x=jump(x,d[x]-d[Lca]-1);
}
if (d[x]-d[Lca]-1>=1)
{
S=find2(x,d[x]-d[Lca]-1)-d[Lca]+(d[Y]-d[Lca]);
ans=max(ans,S);
}
if (d[y]-d[Lca]-1>=1)
{
S=d[y]+find1(y,d[y]-d[Lca]-1);
ans=max(ans,S);
}
// ---
x=jump(x,d[x]-d[Lca]-1);
y=jump(y,d[y]-d[Lca]-1);
if (f[x]<f[y] || f[x]==f[y] && x>y)
swap(x,y);
if (x==G[Lca][1] && y==G[Lca][3])
ans=max(ans,G[Lca][4]+d[Y]-d[Lca]);
else
if (x==G[Lca][1])
ans=max(ans,G[Lca][2]+d[Y]-d[Lca]);
else
ans=max(ans,G[Lca][0]+d[Y]-d[Lca]);
}
printf("%d\n",ans);
}
}