Luogu 4323 [JSOI2016]独特的树叶

本文详细介绍了树哈希算法的应用,通过将每个节点的哈希值与其树的大小结合,来判断两棵树是否相同。利用set集合存储哈希值,并采用换根法减少计算复杂度至近似O(nlogn),提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

新技能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("\n");   */
    
    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\n", i), 0;
    }
    
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/CzxingcHen/p/9509820.html

内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值