一棵樹一共有3*10^5個結點,標號爲1~N,接下來有3*10^5個詢問,給出兩個數字L,R,問標號L到R的最近公共祖先是幾號結點,默認1號結點爲樹根。
首先要注意一個問題,這裏有10^5數量級的點,如果退化成一條鏈,在進行dfs的時候就會爆棧,解決方法有3,bfs或者手動dfs或者加黑科技
<span style="font-size:14px;">#pragma comment(linker, "/STACK:102400000,102400000")</span>
注:黑科技只能在C++編譯器使用,G++沒有這個優化
因爲是連續的區間查詢,比較容易想到的就是使用線段樹來維護,當查詢到兩個子段時,只要在合併的時候求一下它們的公共祖先即可。每次查詢的線段樹操作是O(logn)的複雜度,而對於LCA則可以使用在線倍增法。這樣查詢的過程就是O(log^2n)。
O(n)建樹,整個查詢爲O(Qlog^2n),複雜度爲O(Qlog^2n)。大約爲10^7~8。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define N 300010
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,ls
#define rson mid+1,r,rs
#pragma comment(linker, "/STACK:102400000,102400000")
struct node{
int fa;
}Tree[N<<2];
vector<int>G[N];
int dep[N],fa[N][20];
void dfs(int u,int f,int d){
fa[u][0] = f;
dep[u] = d;
for(int i = 0;i<G[u].size();i++){
int v = G[u][i];
if(v!=f){
dfs(v,u,d+1);
}
}
}
int LCA(int a,int b){
int i,j;
if(a == -1) return b;
if(b == -1) return a;
if(dep[a] < dep[b]) swap(a,b);
for(i = 0;(1<<i) <= dep[a];i++);
i--;
for(j = i;j >= 0;j--)
if(dep[a]-(1<<j)>=dep[b])
a = fa[a][j];
if(a == b) return a;
for(j = i;j >= 0;j--){
if(fa[a][j]!=-1&&fa[a][j]!=fa[b][j]){
a = fa[a][j];
b = fa[b][j];
}
}
return fa[a][0];
}
void pushup(int rt){
Tree[rt].fa = LCA(Tree[ls].fa,Tree[rs].fa);
}
void build(int L,int R,int l,int r,int rt){
int mid;
if(l == r){
Tree[rt].fa = l;
return ;
}
mid = (l + r) >> 1;
build(L,R,lson);
build(L,R,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
int mid;
if(L <= l && r <= R){
return Tree[rt].fa;
}
mid = (l + r) >> 1;
int a,b;
a = b = -1;
if(L <= mid) a = query(L,R,lson);
if(R > mid) b = query(L,R,rson);
int ret = LCA(a,b);
return ret;
}
void init(int n){
memset(fa,-1,sizeof(fa));
for(int i = 0;i <= n+1;i++) G[i].clear();
}
void init2(int n){
int i,j;
for(int j = 1;(1<<j)<= n;j++){
for(int i = 1;i <= n;i++){
if(fa[i][j-1]!=-1) fa[i][j] = fa[fa[i][j-1]][j-1];
}
}
}
int main(){
int n,u,v,ans,q;
while(~scanf("%d",&n)){
init(n);
for(int i = 1;i < n;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,1,1);
init2(n);
build(1,n,1,n,1);
scanf("%d",&q);
for(int i = 0;i < q;i++){
scanf("%d%d",&u,&v);
ans = query(u,v,1,n,1);
cout<<ans<<endl;
}
}
return 0;
}