zoukankan      html  css  js  c++  java
  • [十二省联考2019]春节十二响

    qwq

    题目大意:给出一棵树,要求把这棵树分为若干个集合,集合中不能包含祖先-后代关系,使每个集合中的最大值之和最小。

    - 25分

    subtask里有一种链的情况,且1不一定是链的一个端点。也就是说,树是一个根节点连着两条链。

    假设两条链的点数分别为$m,n(m>n)$。这种情况里,前$n$个点可以两两分为一个集合,后$(m-n)$个点和根节点各自独立为一个集合。

    所以,可以把两条链看作两个优先队列,每次比较它们的$top$,把小的向大的合并为一条链,最后再加上根节点。

    答案即为$sigma(i=2$~$n)max(w[mi],w[ni] + sigma(i=m-n+1$~$m)w[mi] + w[1]$

    考场上半个小时码完了qwq

    然而不知道当时怎么推的,举例的时候以为这个思路是错的就没往下想

    - 60分

    其实这种做法可以由特殊推广到一般。

    对于一个有若干个子链的点,可以把这些链两两合并,成为一条链。树上的每个子树,都可以用这种方法合并为一条链。

    所以每个节点都开一个优先队列,对于一个根节点,首先遍历它的每一棵子树(链),将这条链($q[v]$)与当前根节点所连的最大链(记为$q[u]$)比较,若$q[v].size>q[u].size$则交换。

    将较小的链($q[v]$)合并到较大的链($q[u]$)。遍历所有子树后,将根节点加入$q[u]$。

    void dfs(int u) {
        for(int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            dfs(v);
            if(q[v].size() > q[u].size()) swap(q[u],q[v]);
            int cnt = 0;
            while(!q[v].empty()) {
                tem[++cnt] = max(q[u].top(),q[v].top());
                q[u].pop();
                q[v].pop();
            }
            for(int i = 1; i <= cnt; i++)
                q[u].push(tem[i]);
        }
        q[u].push(w[u]);
    }
    关键代码(60)

    - 100分

    这种做法是很麻烦的。想象一条链的情况,需要每次比较儿子和父亲,交换儿子和父亲,把父亲加入队列…

    因为最下面的儿子是最先遍历到的,所以可以看作把父亲不停地加入儿子的链。

    每次直接把第一个儿子作为最大链;记录每个点的编号,把儿子的编号传递给父亲

    void dfs(int u) {
        id[u] = u;
        for(int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            dfs(v);
            if(i == head[u]){
                id[u] = id[v];
                continue;
            }
           ……
        }
        q[id[u]].push(w[u]);
    }

    这样就快很多啦w

    代码如下

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #define MogeKo qwq
    #define ll long long
    using namespace std;
    const int maxn = 2e5+10;
    
    int n,f,cnt;
    ll w[maxn],tem[maxn],id[maxn];
    ll ans;
    int head[maxn],to[maxn],nxt[maxn];
    priority_queue <ll> q[maxn];
    
    void add(int x,int y) {
        to[++cnt] = y;
        nxt[cnt] = head[x];
        head[x] = cnt;
    }
    
    void dfs(int u) {
        id[u] = u;
        for(int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            dfs(v);
            if(i == head[u]) {
                id[u] = id[v];
                continue;
            }
            if(q[id[v]].size() > q[id[u]].size()) swap(id[u],id[v]);
            int cnt = 0;
            while(!q[id[v]].empty()) {
                tem[++cnt] = max(q[id[u]].top(),q[id[v]].top());
                q[id[u]].pop();
                q[id[v]].pop();
            }
            for(int i = 1; i <= cnt; i++)
                q[id[u]].push(tem[i]);
        }
        q[id[u]].push(w[u]);
    }
    
    int main() {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
            scanf("%lld",&w[i]);
        for(int i = 1; i <= n-1; i++) {
            scanf("%d",&f);
            add(f,i+1);
        }
        dfs(1);
        while(!q[id[1]].empty()) {
            ans += q[id[1]].top();
            q[id[1]].pop();
        }
        printf("%lld",ans);
        return 0;
    }
    View Code

    不知道为啥Luogu把这题评成黑的...明明就queue+一个dfs,才60行代码...

  • 相关阅读:
    C++之Static与Const
    LInux主机与虚拟机网络链接
    C#数据类型与数据类型转化
    C#网编Console(二)
    C#网编Winform(三)
    C#网编基础类与API(一)
    C实现CPU大小端判断
    QT程序图标设置
    四、初识Socket套接字API
    C++之继承(二)
  • 原文地址:https://www.cnblogs.com/mogeko/p/10691909.html
Copyright © 2011-2022 走看看