链接:https://www.nowcoder.com/acm/contest/161/D
来源:牛客网
题目描述
小N所在城市有n个漂亮的公园。有恰好n-1条双向道路连接这n个公园,保证公园间相互可以通过道路到达。每个公园i都有一个专属的属性c[i],表示这个公园的特色。
现在小N有q个疑问。每次他会有两个特定的特色x和y(这两个数可能相同)。他想知道,假如他随便选取一个特色为x的公园出发,必须走到一个特色为y的公园结束,在最优情况下,他最远能走过多少条道路。换句话说,枚举所有的满足c[p] = x的公园p,所有满足c[q] = y的公园q,求出p,q距离的最大值。
输入描述:
第一行两个整数n和q。
第二行n个整数,第i个整数表示第i个公园对应的特色c[i]。
接下来n-1行,每行两个整数u和v,表示有一条连接公园u和公园v的道路。
接下来q行,每行两个整数x和y,代表小N的一个疑问。
数据保证:n ≤ 105, q ≤ 105, 1 ≤ u, v ≤ n, 0 ≤ c[i], x, y ≤ 109
输出描述:
输出共q行,每行对于小N的一个疑问的答案。注意,假如一个疑问中,不存在一个公园特色为x,或不存在一个公园特色为y,那么输出答案0。代表小N一条边都走不了。
输入:
10 4
9 8 9 8 9 8 7 7 8 7
4 5
5 10
10 3
3 9
9 1
1 8
5 7
10 6
8 2
5 8
8 8
7 9
8 9
输出:
0
7
5
6
原理就是树的直径原理
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
const int DEG=20;
struct edge
{
int v,nxt;
}edge[maxn*2+100];
int head[maxn],cnt=0;
void add_edge(int u,int v)
{
edge[cnt].v=v;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
int fa[maxn][20];
int deg[maxn];
void bfs(int u)
{
queue<int>q;
q.push(u);
deg[u]=1;
fa[u][0]=u;
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=1;i<DEG;i++)
{
fa[now][i]=fa[fa[now][i-1]][i-1];
}
for(int i=head[now];i!=-1;i=edge[i].nxt)
{
int v=edge[i].v;
if(v==fa[now][0])
continue;
deg[v]=deg[now]+1;
fa[v][0]=now;
q.push(v);
}
}
}
int lca(int u,int v)
{
if(deg[u]>deg[v])
swap(u,v);
int hu=deg[u],hv=deg[v];
int tu=u,tv=v;
for(int det=hv-hu,i=0;det;det>>=1,i++)
{
if(det&1)
tv=fa[tv][i];
}
if(tu==tv)
return tu;
for(int i=DEG-1;i>=0;i--)
{
if(fa[tu][i]==fa[tv][i])
continue;
tu=fa[tu][i];
tv=fa[tv][i];
}
return fa[tu][0];
}
int getdis(int xx,int yy)
{
return deg[xx]+deg[yy]-2*deg[lca(xx,yy)];
}
int c[maxn],num[maxn];
int cn=0;
vector<int>p[maxn];
int d[maxn][3];
int getid(int x)
{
int k=lower_bound(num,num+cn,x)-num;
if (k>=cn||num[k]!=x)
return -1;
return k;
}
int main ()
{
int n,q;
while(~scanf("%d%d",&n,&q))
{
cn=0;
for(int i=0;i<=n;i++)
{
head[i]=-1;
p[i].clear();
}
memset(fa,0,sizeof(fa));
memset(deg,0,sizeof(deg));
cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&c[i]);
num[cn++]=c[i];
}
sort(num,num+cn);
cn=unique(num,num+cn)-num;
//printf("!\n");
for(int i=1;i<=n;i++)
{
c[i]=lower_bound(num,num+cn,c[i])-num;
p[c[i]].push_back(i);
}
for(int i=1;i<n;i++)
{
int xx,yy;
scanf("%d%d",&xx,&yy);
add_edge(xx,yy);
add_edge(yy,xx);
}
memset(deg,0,sizeof(deg));
bfs(1);
for(int i=0;i<cn;i++)
{
d[i][0]=d[i][1]=p[i][0];
int len=p[i].size();
for(int j=1;j<len;j++)
{
int xx=getdis(d[i][0],p[i][j]);
int yy=getdis(d[i][1],p[i][j]);
if(xx<yy)
{
swap(xx,yy);
swap(d[i][0],d[i][1]);
}
if(xx>getdis(d[i][0],d[i][1]))
{
swap(d[i][1],p[i][j]);
}
}
}
for(int i=1;i<=q;i++)
{
int xx,yy;
scanf("%d%d",&xx,&yy);
xx=getid(xx);
yy=getid(yy);
if(xx==-1||yy==-1)
printf("0\n");
else
{
int maxx=0;
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
maxx=max(maxx,getdis(d[xx][j],d[yy][k]));
}
}
printf("%d\n",maxx);
}
}
}
}