HDU - 5788 Level Up 主席树 + 树状数组

HDU - 5788

我们考虑把每个点遍历一遍, 把枚举的当前的这个点改成100000对答案的影响。

如果我们把 u 变成 100000, 受到影响的是 u 以及它的祖先,

我们记midu为子树u的中位数, nexmidu为子树u中位数的下一个数。

只有 a[ u ]的值小于等于祖先的mid, 才会改变祖先的薪水, 变成nexmidu。

所以我们用主席树求出每个子树的mid 和 nexmid。 然后dfs一遍整棵树, 用树状数组去更新答案。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;}

int n, a[N];
int needVal[N];
int addVal[N];

vector<int> G[N];
int in[N], ot[N], sz[N], idx;

LL ans, allVal;

struct ChairManTree {
    int Rt[N], treecnt;
    void init() {
        treecnt = 0;
    }
    struct Node {
        int sum, ls, rs;
    } a[N * 20];
    void update(int p, int val, int l, int r, int &x, int y) {
        x = ++treecnt;
        a[x] = a[y];
        a[x].sum += val;
        if(l == r) return;
        int mid = l + r >> 1;
        if(p <= mid) update(p, val, l, mid, a[x].ls, a[y].ls);
        else update(p, val, mid + 1, r, a[x].rs, a[y].rs);
    }
    int query(int k, int l, int r, int x, int y) {
        if(l == r) return l;
        int mid = l + r >> 1;
        if(a[a[x].ls].sum - a[a[y].ls].sum >= k) return query(k, l, mid, a[x].ls, a[y].ls);
        else return query(k - a[a[x].ls].sum + a[a[y].ls].sum, mid + 1, r, a[x].rs, a[y].rs);
    }
} C;

struct Bit {
    LL a[N];
    void init() {
        for(int i = 1; i < N; i++) {
            a[i] = 0;
        }
    }
    inline void update(int x, int v) {
        for(int i = x; i < N; i += i & -i) {
            a[i] += v;
        }
    }
    inline LL sum(int x) {
        LL ans = 0;
        for(int i = x; i; i -= i & -i) {
            ans += a[i];
        }
        return ans;
    }
} Tree;

int dfs(int u) {
    in[u] = ++idx;
    C.update(a[u], 1, 1, 100000, C.Rt[idx], C.Rt[idx - 1]);
    sz[u] = 1;
    for(auto &v : G[u]) {
        dfs(v);
        sz[u] += sz[v];
    }
    ot[u] = idx;
}

void solve(int u) {
    Tree.update(100001 - needVal[u], addVal[u]);
    chkmax(ans, Tree.sum(100000 - a[u] + 1));
    for(auto &v : G[u]) {
        solve(v);
    }
    Tree.update(100001 - needVal[u], -addVal[u]);
}

void init() {
    ans = allVal = idx = 0;
    C.init(); Tree.init();
    for(int i = 1; i <= n; i++) {
        G[i].clear();
    }
}
int main() {
    while(scanf("%d", &n) != EOF) {
        init();
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        for(int i = 2; i <= n; i++) {
            int p; scanf("%d", &p);
            G[p].push_back(i);
        }
        dfs(1);
        for(int i = 1; i <= n; i++) {
            if(sz[i] == 1) {
                needVal[i] = a[i];
                addVal[i] = 100000 - a[i];
                allVal += a[i];
            }
            else {
                int mid = sz[i] + 1 >> 1;
                needVal[i] = C.query(mid, 1, 100000, C.Rt[ot[i]], C.Rt[in[i] - 1]);
                addVal[i] = C.query(mid + 1, 1, 100000, C.Rt[ot[i]], C.Rt[in[i] - 1]) - needVal[i];
                allVal += needVal[i];
            }
        }
        solve(1);
        printf("%lld\n", ans + allVal);
    }
    return 0;
}

/*
*/

 

posted @ 2019-09-09 17:01  NotNight  阅读(224)  评论(0编辑  收藏  举报