ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SGU507. Treediff 题解 树上启发式合并 $O(n \log^2 n)$ 解法(TLE)

2020-11-05 23:34:17  阅读:216  来源: 互联网

标签:set log num2 int 题解 num TLE diff num1


题目链接:https://codeforces.com/problemsets/acmsguru/problem/99999/507

题目大意:

每个叶子节点有一个权值。求所有非叶子节点所在的子树中所有叶子节点的权值的差的绝对值的最小值。

解题思路:

树上启发式合并。

关于求绝对值的差的最小值的解法我是使用 multiset 的,参见 这篇随笔

然后 multiset 的 \(O( \log n )\) 乘上 dsu on tree 的复杂度 \(O(n \log n)\),总的时间复杂度为 \(O(n \log^2 n)\)。

示例代码(虽然目前还是 TLE 的):

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50050;

multiset<int> num_set, diff_set;
void my_add(int x) {
    multiset<int>::iterator it = num_set.lower_bound(x);
    int num1 = -1, num2 = -1;
    if (it != num_set.end()) {
        if (it != num_set.end()) num1 = *it;
        diff_set.insert(num1 - x);
    }
    if (it != num_set.begin()) {
        it --;
        num2 = *it;
        diff_set.insert(x - num2);
    }
    if (num1 != -1 && num2 != -1) {
        it = diff_set.lower_bound(num1 - num2);
        diff_set.erase(it);
    }
    num_set.insert(x);
}
void my_del(int x) {
    multiset<int>::iterator it = num_set.lower_bound(x), it2;
    assert(it != num_set.end() && (*it) == x);
    int num1 = -1, num2 = -1;
    it ++;
    if (it != num_set.end()) {
        num1 = *it;
        it2 = diff_set.lower_bound(num1 - x);
        diff_set.erase(it2);
    }
    it --;
    if (it != num_set.begin()) {
        it --;
        num2 = *it;
        it2 = diff_set.lower_bound(x - num2);
        diff_set.erase(it2);
        it ++;
    }
    if (num1 != -1 && num2 != -1) {
        diff_set.insert(num1 - num2);
    }
    num_set.erase(it);
}
int func_find() {
    int ans = INT_MAX;
    if (num_set.size() < 2) return ans;
    multiset<int>::iterator it = diff_set.begin();
    return *it;
}
int n, m, sz[maxn], val[maxn], res[maxn];
bool big[maxn];
vector<int> g[maxn];
void getsz(int u) {
    sz[u] ++;
    for (auto v: g[u])
        getsz(v), sz[u] += sz[v];
}
void add(int u) {
    if (u >= n-m+1) {
        assert(g[u].size() == 0);
        my_add(val[u]);
    }
    else
        for (auto v: g[u])
            if (!big[v])
                add(v);
}
void del(int u) {
    if (u >= n-m+1) {
        assert(g[u].size() == 0);
        my_del(val[u]);
    }
    else
        for (auto v: g[u])
            if (!big[v])
                del(v);
}
void dfs(int u, bool keep) {
    int mx = -1, bigSon = -1;
    for (auto v: g[u])
        if (sz[v] > mx)
            mx = sz[ bigSon = v ];
    for (auto v: g[u])
        if (v != bigSon)
            dfs(v, false);
    if (bigSon != -1)
        dfs(bigSon, true),
        big[bigSon] = true;
    add(u);
    res[u] = func_find();
    if (bigSon != -1)
        big[bigSon] = false;
    if (!keep)
        del(u);
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 2; i <= n; i ++) {
        int p;
        scanf("%d", &p);
        g[p].push_back(i);
    }
    for (int i = n-m+1; i <= n; i ++) scanf("%d", val+i);
    getsz(1);
    dfs(1, false);
    for (int i = 1; i <= n-m; i ++) printf("%d ", res[i]);
    return 0;
}

标签:set,log,num2,int,题解,num,TLE,diff,num1
来源: https://www.cnblogs.com/quanjun/p/13934611.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有