洛谷 P6374 樹上詢問
阿新 • • 發佈:2021-01-24
技術標籤:LCA
洛 谷 P 6374 樹 上 詢 問 洛谷~~P6374 ~~樹上詢問 洛谷P6374樹上詢問
題目描述 :洛谷 P6374
思路:
- 暴力列舉每個點
i
i
i,判斷
L
C
A
(
a
,
b
)
LCA(a,b)
LCA(a,b)是否=
c
c
c。複雜度
O
(
n
⋅
q
⋅
l
o
g
2
(
n
)
)
O(n·q·log_2(n))
O(n⋅q⋅log2(n)),用腳想想都知道過不了(
能騙一分是一分) - 貌似可以用那幾個特殊資料小搞一波,估計比暴力多個10分吧。(
一分也是分) - 說說正解:
首先,我們假設結點1為樹根,敲一遍 D F S DFS
設dp[x]為以x為根的子樹的節點數。
總共有四種情況:
1. c c c不在 a = > b a=>b a=>b的路徑上,此時答案為0.
2. c c c是 a , b a,b a,b的 L C A LCA LCA,此時答案為c與其祖先們的節點。重點來襲
- c為a~LCA(a,b)路徑上的一點,此時 a n s w e r answer answer=dp[c]-dp[v] v表示v為a所在子樹的根節點(以c為樹根時)
- c為b~LCA(a,b)路徑上的一點,此時 a n s w e r answer answer=dp[c]-dp[v] v表示v為b所在子樹的根節點(以c為樹根時)
程式碼:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#define r register
#define rep(i,x,y) for(r int i=x;i<=y;++i)
#define per(i,x,y) for(r int i=x;i>=y;--i)
using namespace std;
typedef long long ll;
const int V=5*1e5+100;
ll n,q,x,y,z,top;
ll f[V][23],d[V],dp[V],head[V];
struct node
{
ll next,to;
}e[V<<1];
void add(ll x,ll y)
{
e[++top]=node{head[x],y};
head[x]=top;
}
void dfs(ll x,ll y)
{
d[x]=d[y]+1;
dp[x]=1;
f[x][0]=y;
for(r ll i=head[x];i;i=e[i].next)
{
ll v=e[i].to;
if(v!=y)
{
dfs(v,x);
dp[x]+=dp[v]; //子樹大小
}
}
}
ll LCA(ll x,ll y) //倍增求LCA
{
if(d[x]>d[y]) swap(x,y);
ll len=d[y]-d[x],k=20,t=1<<k;
while(len)
{
if(len>=t)
len-=t,y=f[y][k];
t>>=1,--k;
}
if(x==y) return x;
per(k,20,0)
if(f[x][k]!=f[y][k])
{
x=f[x][k];
y=f[y][k];
}
return f[x][0];
}
bool check(ll x,ll y, ll z) //判斷y是否在x-->z的路徑上
{
ll k=LCA(x,z);
return ((LCA(x,y)==y)||(LCA(y, z)==y))&&LCA(y,k)==k;
}
ll size(ll x,ll y) //找到點“v”
{
if(x==y) return 0;
ll len=d[x]-d[y],k=20,t=1<<k;
per(i,20,0)
if(d[f[x][i]]>d[y])
x=f[x][i];
return dp[x];
}
int main()
{
scanf("%lld%lld",&n,&q);
rep(i,1,n-1)
{
scanf("%lld%lld",&x,&y);
add(x,y),add(y,x);
}
dfs(1,0);
rep(j,1,20)
rep(i,1,n)
f[i][j]=f[f[i][j-1]][j-1]; //LCA的預處理
rep(i,1,q)
{
scanf("%lld%lld%lld",&x,&y,&z);
ll v=LCA(x,y);
if(v==z) printf("%lld\n",n-size(x,v)-size(y,v));
else if(check(x,z,v)) printf("%lld\n",dp[z]-size(x,z));
else if(check(y,z,v)) printf("%lld\n",dp[z]-size(y,z));
else printf("0\n");
}
return 0;
}