CF-832-D- Misha, Grisha and Underground(lca倍增,板子+規律)
題目連結:http://codeforces.com/problemset/problem/832/D
Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations connected with n - 1 routes so that each route connects two stations, and it is possible to reach every station from any other.
The boys decided to have fun and came up with a plan. Namely, in some day in the morning Misha will ride the underground from station s
The boys have already chosen three stations a, b and c for each of several following days, one of them should be station s on that day, another should be station f, and the remaining should be station t. They became interested how they should choose these stations s
Input
The first line contains two integers n and q (2 ≤ n ≤ 105, 1 ≤ q ≤ 105) — the number of stations and the number of days.
The second line contains n - 1 integers p2, p3, ..., pn (1 ≤ pi ≤ n). The integer pi means that there is a route between stations pi and i. It is guaranteed that it's possible to reach every station from any other.
The next q lines contains three integers a, b and c each (1 ≤ a, b, c ≤ n) — the ids of stations chosen by boys for some day. Note that some of these ids could be same.
Output
Print q lines. In the i-th of these lines print the maximum possible number Grisha can get counting when the stations s, t and f are chosen optimally from the three stations on the i-th day.
Examples
input
3 2 1 1 1 2 3 2 3 3
output
2 3
input
4 1 1 2 3 1 2 3
output
2
Note
In the first example on the first day if s = 1, f = 2, t = 3, Misha would go on the route 1 2, and Grisha would go on the route 3 1 2. He would see the text at the stations 1 and 2. On the second day, if s = 3, f = 2, t = 3, both boys would go on the route 3 1 2. Grisha would see the text at 3 stations.
In the second examle if s = 1, f = 3, t = 2, Misha would go on the route 1 2 3, and Grisha would go on the route 2 3 and would see the text at both stations.
題目大意:給出n個車站,m次訪問
n-1個數字,意思為i-pi的道路是通路(雙向)
之後是m次訪問,輸入三個點,任意一個是終點,另兩個是起點,找出重合點最多的路線,輸出重合點的數量
其實並不難,關鍵是如何確定重合最多的點,因為就三個點,可以直接處理處三個情況,然後取最大的即可;
對於a,b,c三點;很容易從圖中看到,如果以a,b為起點,那麼(lca(a,c)+lca(b,c)-lca(a,b))/2就是他們的重合的邊了,那麼因為有三條邊,直接找出三條邊的長度然後取最長的那個即可:
ac:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
//#include<map>
//#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
const int MAXN=101000;
const int INF=0x3f3f3f3f;
const ll mod=1e9+7;
struct node{
int v,w,nxt;
node(int _v=0,int _nxt=0):
v(_v),nxt(_nxt){}
}edge[MAXN<<1];
int head[MAXN],ecnt;
int fa[MAXN][30],deep[MAXN];
int len[MAXN][30];
int n,m;
void intt()
{
clean(len,0);
clean(head,-1);
clean(deep,0);
clean(fa,-1);
ecnt=0;
}
void add(int u,int v)
{
edge[ecnt]=node(v,head[u]);
head[u]=ecnt++;
}
/*---------------板子-----------------*/
void dfs(int u)
{
for(int i=head[u];i+1;i=edge[i].nxt)
{
int temp=edge[i].v;
if(deep[temp]==0)
{
deep[temp]=deep[u]+1;
fa[temp][0]=u;
len[temp][0]=1;
int up=0,pre=u;
while(fa[pre][up]>=0)
{
fa[temp][up+1]=fa[pre][up];
len[temp][up+1]=len[temp][up]+len[pre][up];
pre=fa[pre][up++];
}
dfs(temp);
}
}
}
int lca(int a,int b)
{
int ans=0;
if(deep[a]<deep[b])
swap(a,b);
int lim=log2(deep[a])+1;
for(int i=lim;i>=0;--i)
{
if(deep[fa[a][i]]>=deep[b])
{
ans+=len[a][i];
a=fa[a][i];
}
}
if(a==b)
return ans;
for(int i=lim;i>=0;--i)
{
if(fa[a][i]!=fa[b][i])
{
ans=ans+len[a][i];
a=fa[a][i];
ans=ans+len[b][i];
b=fa[b][i];
}
}
ans=ans+len[a][0]+len[b][0];
return ans;
}
int main()
{
std::ios::sync_with_stdio(false);
intt();
cin>>n>>m;
int num;
for(int i=2;i<=n;++i)
{
cin>>num;
add(i,num);
add(num,i);
}
deep[1]=1;
dfs(1);
int a,b,c;
for(int i=1;i<=m;++i)
{
cin>>a>>b>>c;
//以任意點為終點,另兩個點為起點,重合的最多的點
int lab=lca(a,b);
int lac=lca(a,c);
int lbc=lca(b,c);
int ans1=(lac+lbc-lab)/2+1;
int ans2=(lac+lab-lbc)/2+1;
int ans3=(lab+lbc-lac)/2+1;
cout<<max(ans1,max(ans2,ans3))<<endl;
}
}