HDU 5266 pog loves szh III

點擊打開鏈接

一棵樹一共有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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章