猴猴的比赛 dfs序

猴猴的比赛 dfs序

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

(nle 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;
}
原文地址:https://www.cnblogs.com/santiego/p/11777458.html