zoukankan      html  css  js  c++  java
  • 51nod 1681 公共祖先 | 树状数组

    51nod 1681 公共祖先

    有一个庞大的家族,共n人。已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边)。
    在另一个未知的平行宇宙,这n人的祖辈关系仍然是树形结构,但他们相互之间的关系却完全不同了,原来的祖先可能变成了后代,后代变成的同辈……
    两个人的亲密度定义为在这两个平行宇宙有多少人一直是他们的公共祖先。
    整个家族的亲密度定义为任意两个人亲密度的总和。
    Input
    第一行一个数n(1<=n<=100000)
    接下来n-1行每行两个数x,y表示在第一个平行宇宙x是y的父亲。
    接下来n-1行每行两个数x,y表示在第二个平行宇宙x是y的父亲。
    Output
    一个数,表示整个家族的亲密度。
    Input示例
    5
    1 3
    3 5
    5 4
    4 2
    1 2
    1 3
    3 4
    1 5
    Output示例
    6

    先遍历第一棵树,按DFS序给每个节点标号,并记录每棵子树标号所处的范围的左端点 l[i] 和右端点 r[i]。
    然后遍历第二棵树,分别记录遍历一棵子树前后 l[i]~r[i] 范围内有多少点被遍历过,设二者之差为x,ans += x * (x - 1) / 2 即可。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    template <class T>
    void read(T &x){
        char c;
        while(c = getchar(), c < '0' || c > '9');
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
    }
    template <class T>
    void write(T x){
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    
    const int N = 100005;
    int n, l[N], r[N], idx, sum[N];
    int ecnt, adj[2][N], nxt[2][N], go[2][N];
    ll ans;
    bool notroot[N];
    
    void add(int u, int v, bool x){
        notroot[v] = 1;
        go[x][++ecnt] = v;
        nxt[x][ecnt] = adj[x][u];
        adj[x][u] = ecnt;
    }
    void dfs1(int u, int pre){
        l[u] = ++idx;
        for(int e = adj[0][u]; e; e = nxt[0][e])
            if(go[0][e] != pre)
                dfs1(go[0][e], u);
        r[u] = idx;
    }
    void change(int p){
        while(p <= n) sum[p]++, p += p & -p;
    }
    int ask(int p){
        int ret = 0;
        while(p) ret += sum[p], p -= p & -p;
        return ret;
    }
    void dfs2(int u, int pre){
        change(l[u]);
        int old = ask(r[u]) - ask(l[u] - 1);
        for(int e = adj[1][u]; e; e = nxt[1][e])
            if(go[1][e] != pre)
                dfs2(go[1][e], u);
        int now = ask(r[u]) - ask(l[u] - 1);
        int delta = now - old;
        ans += (ll) delta * (delta - 1) / 2;
    }
    
    int main(){
        
        read(n);
        for(int i = 1, u, v; i < n; i++)
            read(u), read(v), add(u, v, 0);
        for(int i = 1; i <= n; i++)
            if(!notroot[i])
                dfs1(i, 0);
        memset(notroot, 0, sizeof(notroot));
        for(int i = 1, u, v; i < n; i++)
            read(u), read(v), add(u, v, 1);
        for(int i = 1; i <= n; i++)
            if(!notroot[i])
                dfs2(i, 0);
        write(ans), putchar('
    ');
        
        return 0;
    }
    
  • 相关阅读:
    Servlet会话管理一(URL重写和表单隐藏域)
    Eclipse自动补全设置
    String类为什么设计成不可变的
    部署描述符(web.xml)和标注(annotation)
    html中 &nbsp; 和空格的区别
    HTML的基本知识点
    Eclipse中配置Tomcat服务器并创建标准Web目录
    Sevlet处理HTML表单
    Servlet API
    Servlet开发的三种方法
  • 原文地址:https://www.cnblogs.com/RabbitHu/p/51nod1681.html
Copyright © 2011-2022 走看看