zoukankan      html  css  js  c++  java
  • Luogu 4323 [JSOI2016]独特的树叶

    新技能get

    树哈希,考虑到两棵树相同的条件,把每一个结点的哈希值和树的siz写进哈希值里去。

    做出A树每一个结点为根时的树的哈希值丢进set中,然后暴力枚举B树中度数为1的点,求出删掉这个点之后的哈希值是否相同。

    暴力算哈希是$O(n^{2})$的,考虑换根法,一个点作根的时候它的子树中的信息是不会变的,唯一的改变就是它的父亲及往上变成了它的新的一棵子树,这样我们可以递推出每一个结点的父亲作它的子树时的哈希值。

    所以先自下到上哈希一遍,再重新自上到下算一遍,算父亲作儿子的哈希值就相当于挖掉一个子树,具体可以看代码实现。

    因为哈希过程中的$sort$,时间复杂度为近似的$O(nlogn)$

    感觉你谷评分好乱

    Code:

    #include <set>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef unsigned long long ull;
    
    const int N = 1e5 + 5;
    const ull sed = 12589;
    
    int m;
    ull q2[N], bin[N];
    set <ull> s;
    
    struct Node {
        int now;
        ull val;
        
        Node (int x = 0, ull y = 0) : now(x), val(y) {}
        
        friend bool operator < (const Node &u, const Node &v) {
            return u.val < v.val;
        }
        
    } q1[N];
    
    inline void read(int &X) {
        X = 0;
        char ch = 0;
        int op = 1;
        for(; ch > '9'|| ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    struct Tree {
        int n, tot, head[N], fa[N], siz[N], deg[N];
        ull v[N], f[N], rt[N], suf[N], pri[N];
        
        struct Edge {
            int to, nxt;
        } e[N << 1];
        
        inline void add(int from, int to) {
            e[++tot].to = to;
            e[tot].nxt = head[from];
            head[from] = tot;
        }
        
        inline void addEdge(int x, int y) {
            deg[x]++, deg[y]++;
            add(x, y), add(y, x);
        }
        
        inline void init(int now) {
            n = now, tot = fa[1] = 0;
            for(int i = 1; i <= n; i++) 
                head[i] = deg[i] = 0;
            for(int x, y, i = 1; i < n; i++) {
                read(x), read(y);
                addEdge(x, y);
            }
        }
        
        void dfs1(int x) {
            siz[x] = 1;
            for(int i = head[x]; i; i = e[i].nxt) {
                int y = e[i].to;
                if(y == fa[x]) continue;
                fa[y] = x;
                dfs1(y);
                siz[x] += siz[y];
            }
            
            int cnt = 0;
            for(int i = head[x]; i; i = e[i].nxt) {
                int y = e[i].to;
                if(y == fa[x]) continue;
                q2[++cnt] = v[y];
            }
            
            sort(q2 + 1, q2 + cnt + 1);
            v[x] = 0;
            for(int i = 1; i <= cnt; i++)
                v[x] = v[x] * sed + q2[i];
            v[x] = v[x] * sed + (ull)siz[x];
        }
        
        void dfs2(int x) {
            int cnt = 0;
            if(x > 1) q1[++cnt] = Node(fa[x], f[x]);
            for(int i = head[x]; i; i = e[i].nxt) {
                int y = e[i].to;
                if(y == fa[x]) continue;
                q1[++cnt] = Node(y, v[y]);
            }
            
            sort(q1 + 1, q1 + cnt + 1);
            pri[0] = 0;
            for(int i = 1; i <= cnt; i++)
                pri[i] = pri[i - 1] * sed + q1[i].val;
            suf[cnt + 1] = 0;
            for(int i = cnt; i >= 1; i--)
                suf[i] = suf[i + 1] + q1[i].val * bin[cnt - i];
            
            for(int i = 1; i <= cnt; i++) {
                if(q1[i].now == fa[x]) continue;
                f[q1[i].now] = pri[i - 1] * bin[cnt - i] + suf[i + 1];
                f[q1[i].now] = f[q1[i].now] * sed + (ull)(n - siz[q1[i].now]);
            }
            
            for(int i = head[x]; i; i = e[i].nxt) {
                int y = e[i].to;
                if(y == fa[x]) continue;
                dfs2(y);
            }
        }
        
        void calc() {
            dfs1(1), dfs2(1);
            for(int x = 1; x <= n; x++) {
                int cnt = 0;
                for(int i = head[x]; i; i = e[i].nxt) {
                    int y = e[i].to;
                    if(y == fa[x]) continue;
                    q2[++cnt] = v[y];
                }
                if(x != 1) q2[++cnt] = f[x];
                
                sort(q2 + 1, q2 + 1 + cnt);
                rt[x] = 0;
                for(int i = 1; i <= cnt; i++)
                    rt[x] = rt[x] * sed + q2[i];
                rt[x] = rt[x] * sed + (ull)n;
            }
        }
        
    } a, b;
    
    int main() {
        read(m);
        
        bin[0] = 1;
        for(int i = 1; i <= m + 2; i++)
            bin[i] = bin[i - 1] * sed;
            
        a.init(m), a.calc();
        b.init(m + 1), b.calc();
        
    /*    for(int i = 1; i <= m; i++)
            printf("%llu ", a.rt[i]);
        printf("
    ");   */
        
        for(int i = 1; i <= m; i++)
            s.insert(a.rt[i]);
        
        for(int i = 1; i <= m + 1; i++) {
            if(b.deg[i] != 1) continue;
            if((i != 1 && s.find(b.f[i]) != s.end()) 
            || (i == 1 && s.find(b.v[b.e[b.head[1]].to]) != s.end()))
                return printf("%d
    ", i), 0;
        }
        
        return 0;
    }
    View Code
  • 相关阅读:
    通过盘古分词自定义规则功能实现软件版本号的提取
    Js event事件在IE、FF兼容性问题
    Android动画效果 translate、scale、alpha、rotate 切换Activity动画 控件位置调整
    iPhone代码片段收集(持续更新)
    Activity之间的相互调用与传递参数
    android如何拍照以及返回拍的图片(经过验证的实际例子)
    Android API :SMS短信服务处理和获取联系人
    实现Android的消息通知栏
    iPhone开发 调用摄像头进行拍照等操作
    Android模拟 HTTP multipart/formdata 请求协议信息实现图片上传
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9509820.html
Copyright © 2011-2022 走看看