ICode9

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

Interstellar 题解

2021-05-12 21:35:14  阅读:139  来源: 互联网

标签:ch int 题解 Interstellar long tag mx dp


一、题目:



二、思路:

在没看数据范围之前,这道题有一个十分显然的树形DP做法。

设 \(dp(x)\) 表示 \(x\) 及其子树内所能获得的最大代价(题目为什么要使代价最大化呢?),于是有转移方程

\[dp(x)=\max_{y\in son(x)}\{dp(y)+w(x,y)\}+\sum_{y\in son(x)} (dp(y)+w(x,y)) \]

时间复杂度 \(O(n)\),这题不就解决了吗?

然后看到数据范围 \(0\leq c_i\leq 10^{18}\),也就是说每条边的权值最大可以是 \(2^{10^{18}}\),当场去世。

于是考虑用 set 维护每条边的权值中有哪几个2的幂次。加法和比较大小都类似于高精度。

考虑这样的复杂度为什么是对的,因为每条边至多只会贡献一个2的幂次,而且加法每进一位都会少一个1,所以每次均摊复杂度是 \(O(1)\) 的。如果我们再用启发式合并,那总的复杂度就是 \(O(n\log^2 n)\)的。比较大小也一样。

再考虑我们还要取出最大的数进行累加,这时候相当于对一个数乘2,也就是每一个2的幂次都会左移。暴力移肯定不行,考虑使用懒标记。

然后呢?然后就没了。

三、启示:

其实这样的做法很容易想到,这启发我们需要认真分析复杂度,而且当不方便实时维护的时候一定要想到懒标记,有时候能解决很多问题。

四、代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>

using namespace std;

#define FILEIN(s) freopen(s".in", "r", stdin)
#define FILEOUT(s) freopen(s".out", "w", stdout)

inline long long read(void) {
    long long x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return f * x;
}

const int maxn = 1e5 + 5, mod = 998244353;

int n, tot = 1, head[maxn];
long long ans[maxn];

struct Edge {
    int y, next;
    long long w;
    Edge() {}
    Edge(int _y, int _next, long long _w) : y(_y), next(_next), w(_w) {}
}e[maxn << 1];

struct Node {
    set<long long>S;
    long long tag;
    inline void insert(long long p) {
        p -= tag;
        while (S.find(p) != S.end()) {
            S.erase(p);
            ++ p;
        }
        S.insert(p);
    }
    inline friend bool operator <(const Node&a, const Node&b) {
        if (b.S.size() == 0) return 0;
        if (a.S.size() == 0) return 1;
        set<long long>::iterator i1 = a.S.end(), i2 = b.S.end();
        -- i1; -- i2;
        while ((*i1) + a.tag == (*i2) + b.tag) {
            if (i2 == b.S.begin()) return 0;
            if (i1 == a.S.begin()) return 1;
            -- i1; -- i2;
        }
        return (*i1) + a.tag < (*i2) + b.tag;
    }
}dp[maxn];

inline long long power(long long a, long long b) {
    long long res = 1;
    for (; b; b >>= 1) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
    }
    return res;
}

inline void connect(int x, int y, long long w) {
    e[++ tot] = Edge(y, head[x], w);
    head[x] = tot;
}

void dfs(int x, int fa) {
    int mx = -1;

    for (int i = head[x]; i; i = e[i].next) {
        int y = e[i].y;
        if (y == fa) continue;
        dfs(y, x);
        ans[y] += power(2, e[i].w);
        dp[y].insert(e[i].w);
        if (mx == -1 || dp[mx] < dp[y]) mx = y;
    }

    if (mx != -1) {
        ++ dp[mx].tag;
        (ans[mx] *= 2) %= mod;
    }

    for (int i = head[x]; i; i = e[i].next) {
        int y = e[i].y;
        if (y == fa) continue;

        if (dp[y].S.size() > dp[x].S.size()) swap(dp[y], dp[x]);

        for (set<long long>::iterator it = dp[y].S.begin(); it != dp[y].S.end(); ++ it) {
            dp[x].insert(*it + dp[y].tag);
        }

        (ans[x] += ans[y]) %= mod;
    }

}

int main() {
    FILEIN("a"); FILEOUT("a");
    n = read();
    for (int i = 1; i < n; ++ i) {
        int p = read(); long long w = read();
        connect(i + 1, p, w);
        connect(p, i + 1, w);
    }
    dfs(1, 0);
    printf("%lld\n", ans[1]);
    return 0;
}

标签:ch,int,题解,Interstellar,long,tag,mx,dp
来源: https://www.cnblogs.com/little-aztl/p/14761774.html

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

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

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

ICode9版权所有