其他分享
首页 > 其他分享> > 猴猴的比赛 dfs序

猴猴的比赛 dfs序

作者:互联网

猴猴的比赛 dfs序

两颗\(n\)节点的树,不相同,问多少点对\((u,v)\)在两棵树上均满足路径\(v\)在\(u\)子树中

\(n\le 10^5\)

暴力:

\(n^2\)暴力枚举点对用\(dfs\)序\(O(1)\)判断是非满足条件,或者用欧拉序\(O(1)\)求lca

正解:

先跑第一棵树,求出其\(dfs\)序,记录下节点\(i\)的\(dfs\)序开始与结束位置。

然后跑第二棵树,维护一个下标为\(dfs\)序的树状数组,每次第一次遍历到节点\(i\)时,我们统计在当前节点的\(dfs\)序之前(即满足在第一棵树上节点\(i\)在\(j\)的子树中)且在当前这第二棵树上已经遍历过的节点(即满足在第二棵树上节点\(i\)在\(j\)的子树中)的个数,加入到答案。这个过程相当于统计每个\((u,v)\)中的\(v\)。

具体看代码实现吧。

#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;
}

标签:head,比赛,int,猴猴,dfs,dfn,MAXN,tot
来源: https://www.cnblogs.com/santiego/p/11777458.html