猴猴的比賽 dfs序

猴猴的比賽 dfs序

兩顆\(n\)節點的樹,不相同,問多少點對\((u,v)\)在兩棵樹上均知足路徑\(v\)\(u\)子樹中數組

\(n\le 10^5\)spa

暴力:code

\(n^2\)暴力枚舉點對用\(dfs\)\(O(1)\)判斷是非知足條件,或者用歐拉序\(O(1)\)求lcaget

正解:io

先跑第一棵樹,求出其\(dfs\)序,記錄下節點\(i\)\(dfs\)序開始與結束位置。class

而後跑第二棵樹,維護一個下標爲\(dfs\)序的樹狀數組,每次第一次遍歷到節點\(i\)時,咱們統計在當前節點的\(dfs\)序以前(即知足在第一棵樹上節點\(i\)\(j\)的子樹中)且在當前這第二棵樹上已經遍歷過的節點(即知足在第二棵樹上節點\(i\)\(j\)的子樹中)的個數,加入到答案。這個過程至關於統計每一個\((u,v)\)中的\(v\)cli

具體看代碼實現吧。遍歷

#include <cstdio>
#define MAXN 100001
using namespace std;
inline int read(){
    char ch=getchar();int s=0;
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') s=s*10+(ch^'0'), ch=getchar();
    return s;
}
int n;
int tre[MAXN];
void add(int x, int val){
    while(x<=n)
        tre[x]+=val,x+=x&(-x);
}
int get_sum(int x){
    int res=0;
    while(x>0)
        res+=tre[x],x-=x&(-x);
    return res;
}
int dfn[MAXN],dfn_out[MAXN],cnt;
int ans[MAXN];
namespace tre1 {
    int head[MAXN],nxt[MAXN*2],vv[MAXN*2],tot;
    inline void add_edge(int u, int v){
        vv[++tot]=v;
        nxt[tot]=head[u];
        head[u]=tot;
    }
    void dfs(int u, int fa){
        dfn[u]=++cnt;
        for(int i=head[u];i;i=nxt[i]){
            int v=vv[i];
            if(v==fa) continue;
            dfs(v, u);
        }
        dfn_out[u]=cnt;
    }
}
namespace tre2 {
    int head[MAXN],nxt[MAXN*2],vv[MAXN*2],tot;
    inline void add_edge(int u, int v){
        vv[++tot]=v;
        nxt[tot]=head[u];
        head[u]=tot;
    }
    void solve(int u, int fa){
        ans[u]=get_sum(dfn[u]-1);
        add(dfn[u], 1);
        add(dfn_out[u], -1);
        for(int i=head[u];i;i=nxt[i]){
            int v=vv[i];
            if(v==fa) continue;
            solve(v, u);
        }
        add(dfn[u], -1);
        add(dfn_out[u], 1);
    }
}
int main(){
    //freopen("climb.in", "r", stdin);
    //freopen("climb.out", "w", stdout);
    n=read();
    for(int i=1;i<n;++i){
        int u=read(),v=read();
        tre1::add_edge(u, v);
        tre1::add_edge(v, u);
    }
    for(int i=1;i<n;++i){
        int u=read(),v=read();
        tre2::add_edge(u, v);
        tre2::add_edge(v, u);
    }
    tre1::dfs(1, 1);
    tre2::solve(1, 1);
    long long sum=0;
    for(int i=1;i<=n;++i) sum+=ans[i];
    printf("%lld", sum);
    return 0;
}
相關文章
相關標籤/搜索