• [十二省联考2019]春节十二响(启发式合并)


    • 链的情况我们的做法是从两个子树中各取出最大的, 贡献答案是两个的较大值, 直到其中一个没有数字了, 我们就停止, 然后加入还有数字的那棵子树中所有的数字贡献

    • 显然这是一个类似堆的操作, 同时我们可以将它扩充到许多棵子树的情况, 实际上就是取出每颗子树堆的最大值合并起来

    • 这样的话就能够打出一个用堆模拟的暴力(能A)

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<iostream>
    #define ll long long
    #define mmp make_pair
    #define M 200010
    using namespace std;
    int read() {
        int nm = 0, f = 1;
        char c = getchar();
        for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
        return nm * f;
    }
    int sz[M], fa[M], son[M], a[M], n, tmp[M], tp, id[M], tim;
    vector<int> to[M];
    bool cmp(int a, int b)
    {
        return sz[a] > sz[b];
    }
    ll ans = 0;
    priority_queue<int> q[M];
    
    void dfs(int now)
    {
    	id[now] = ++tim;
        for(int i = 0; i < to[now].size(); i++)
        {
            int vj = to[now][i];
            dfs(vj);
        }
        sort(to[now].begin(), to[now].end(), cmp);
        int r = to[now].size() - 1, tp = 0;
        while(1)
        {
        	int maxx = 0;
        	for(int i = 0; i <= r; i++)
        	{
        		int vj = to[now][i];
        		if(q[id[vj]].empty())
        		{
        			r = i - 1;
        			break;
        		}
        		maxx = max(maxx, q[id[vj]].top());
        		q[id[vj]].pop();
        		sz[vj]--;
        	}
        	if(maxx != 0) tmp[++tp] = maxx;
        	if(r <= 0) break;
        }
    	if(to[now].size()) id[now] = id[to[now][0]], sz[now] = sz[to[now][0]];
    	for(int i = 1; i <= tp; i++) q[id[now]].push(tmp[i]);
    	q[id[now]].push(a[now]);
    	sz[now] += tp + 1;
    }
    
    int main() {
    //	freopen("spring.in", "r", stdin);freopen("spring.out", "w", stdout);
        n = read();
        for(int i = 1; i <= n; i++) a[i]  = read();
        for(int i = 2; i <= n; i++) {
            fa[i] = read();
            to[fa[i]].push_back(i);
        }
        dfs(1);
        while(!q[id[1]].empty()) ans += q[id[1]].top(), q[id[1]].pop();
        cout << ans << "
    ";
        return 0;
    }
    /*
    16
    8 9 19 9 13 9 17 8 9 20 20 7 2 12 19 6
    1 2 1 4 3 5 5 8 6 10 3 8 7 4 3
    
    
    */
    
    
    • 排序之后直接用堆合并就能A, 但是这样我不太清楚复杂度是多少
    • 考虑直接合并所有子树和依次合并两个子树效果是一样的
    • 然后我们就可以在合并的时候把小的往大的里面合
    • 然后启发式的复杂度就是两个log的了
    
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<iostream>
    #define ll long long
    #define mmp make_pair
    #define M 200010
    using namespace std;
    int read() {
        int nm = 0, f = 1;
        char c = getchar();
        for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
        return nm * f;
    }
    int sz[M], fa[M], son[M], a[M], n, id[M], tim;
    vector<int> to[M];
    ll ans = 0;
    priority_queue<int> q[M];
    
    void dfs(int now)
    {
        id[now] = ++tim;
        for(int i = 0; i < to[now].size(); i++)
        {
            int vj = to[now][i];
            dfs(vj);
        }
        for(int i = 0; i < to[now].size(); i++)
        {
            int vj = to[now][i];
            if(q[id[now]].size() < q[id[vj]].size()) swap(id[now], id[vj]);
            int m = q[id[vj]].size();
            for(int j = 1; j <= m; j++)
            {
                son[j] = max(q[id[now]].top(), q[id[vj]].top());
                q[id[now]].pop(), q[id[vj]].pop();
            }
            for(int j = 1; j <= m; j++) q[id[now]].push(son[j]);
        }
        q[id[now]].push(a[now]);
        
    }
    
    int main() {
    //	freopen("spring.in", "r", stdin);freopen("spring.out", "w", stdout);
        n = read();
        for(int i = 1; i <= n; i++) a[i]  = read();
        for(int i = 2; i <= n; i++) {
            fa[i] = read();
            to[fa[i]].push_back(i);
        }
        dfs(1);
        while(!q[id[1]].empty()) ans += q[id[1]].top(), q[id[1]].pop();
        cout << ans << "
    ";
        return 0;
    }
    
  • 相关阅读:
    7、【Linux系统编程】阻塞和非阻塞
    css样式
    如果目录不存在就创建
    api图片传输,转成64位字符串进行传输
    c#获取远程图片的方法
    分页
    使用微信js接口的方法 ,以调用相机为例
    某个文件下下面的文件批量改名
    查找本地文件中的特定字符串并替换代码
    第35月第6天 自定义view初始化
  • 原文地址:https://www.cnblogs.com/luoyibujue/p/10668396.html
Copyright © 2020-2023  润新知