题目描述
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);
}
}