【HDU 5052】Yaoge’s maximum profit【树链刨分】

13 篇文章 0 订阅
3 篇文章 0 订阅

        思路:一眼看上去就有点树链刨分的感觉。不过现场时死活就是超时,结果发现long long改成int就过。

      首先我们把树正常的刨成线段树,然后线段树结点保存该区间的最大最小值,还有区间最优解,以及区间逆向最优解,懒操作值。根据这几个值就可以解此题目,复杂度是mlog(n)的。

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N 50004
#define lc (d<<1)
#define rc (d<<1|1)
#define mid (l+r>>1)

struct Tr{
    int re, mx, mi, lz, ni;
}tr[N<<2];

struct E{
    int v, ne;
    E(){}
    E(int _v, int _ne):v(_v), ne(_ne){}
}e[N<<1];

int size, head[N], n, m;
int fa[N], tid[N], top[N], dep[N], sun[N], dfn, sid[N];
int val[N], pre[N];

void init() {
    size = 0;
    memset(tid, -1, sizeof(tid));
    memset(head, -1, sizeof(head));
}

void add(int u, int v) {
    e[size] = E(v, head[u]);
    head[u] = size++;
}

int dfs(int u, int f) {
    int mi = 0, v, i, s = u, c = 1, sd = 0;
    for (i = head[u];~i;i = e[i].ne) {
        v = e[i].v;
        if (v == f) continue;
        int tm = dfs(v, u);
        c += tm;
        if (tm > mi) mi = tm, s = v;
    }
    sun[u] = s;
    return c;
}

void dfs1(int u, int f, int d, int Top) {
    dep[u] = d, fa[u] = f, top[u] = Top, tid[u] = ++dfn, pre[dfn] = u;
    if (tid[sun[u]] == -1) {
        dfs1(sun[u], u, d+1, Top);
    }
    int v, i;
    for (i = head[u];~i;i = e[i].ne) {
        v = e[i].v;
        if (tid[v] != -1) continue;
        dfs1(v, u, d+1, v);
    }
}

inline void Push(int d) {
    tr[d].re = 0;
    tr[d].mi = min(tr[lc].mi, tr[rc].mi);
    tr[d].mx = max(tr[lc].mx, tr[rc].mx);
    tr[d].re = max(tr[d].re, max(tr[lc].re, tr[rc].re));
    tr[d].re = max(tr[d].re, tr[rc].mx-tr[lc].mi);
    tr[d].ni = 0;
    tr[d].ni = max(tr[d].ni, max(tr[lc].ni, tr[rc].ni));
    tr[d].ni = max(tr[d].ni, tr[lc].mx-tr[rc].mi);
}

void build(int d, int l, int r) {
    tr[d].lz = 0;
    if (l == r) {
        tr[d].mi = tr[d].mx = val[pre[l]];
        tr[d].re = tr[d].ni = 0;
        return;
    }
    build(lc, l, mid), build(rc, mid+1, r);
    Push(d);
}

struct Em{
    int re, mi, mx;
    Em(){}
    Em(int _r, int _i, int _x):re(_r), mi(_i), mx(_x){}
    Em operator+(Em a) const {
       Em tm;
       tm.re = max(a.re, re);
       tm.mx = max(a.mx, mx);
       tm.mi = min(a.mi, mi);
       tm.re = max(tm.re, a.mx-mi);
       return tm;
    } 
};

vector<Em>V;

inline void lazy(int d, int l, int r) {
    if (tr[d].lz) {
        tr[lc].lz += tr[d].lz;
        tr[lc].mi += tr[d].lz, tr[lc].mx += tr[d].lz;
        tr[rc].lz += tr[d].lz;
        tr[rc].mi += tr[d].lz, tr[rc].mx += tr[d].lz;
        tr[d].lz = 0;
    }
}

Em query(int d, int l, int r, int L, int R, int k, int ad) {
    if (l == L && r == R) {
        Em tm = Em(k?tr[d].re:tr[d].ni, tr[d].mi, tr[d].mx);
        tr[d].lz += ad, tr[d].mi += ad, tr[d].mx += ad;
        return tm;
    }
    lazy(d, l, r);
    Em tm;
    if (R <= mid) tm = query(lc, l, mid, L, R, k, ad);
    else if (L > mid) tm = query(rc, mid+1, r, L, R, k, ad);
    else {
        Em tl = query(lc, l, mid, L, mid, k, ad);
        Em tr = query(rc, mid+1, r, mid+1, R, k, ad);
        tm.mi = min(tl.mi, tr.mi);
        tm.mx = max(tl.mx, tr.mx);
        tm.re = max(tl.re, tr.re);
        if (k) {
            tm.re = max(tm.re, tr.mx-tl.mi);
        }else {
            tm.re = max(tm.re, tl.mx-tr.mi);
        }
    }
    Push(d);
    return tm;
}

void solve(int u, int v, int k) {
    int re = 0;
    int i = -1;
    V.clear();
    Em tm;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) {
            V.push_back(query(1, 1, dfn, tid[top[v]], tid[v], 1, k));
            v = fa[top[v]];
        }else {
            if (i < 0) tm = query(1, 1, dfn, tid[top[u]], tid[u], 0, k);
            else tm = tm+query(1, 1, dfn, tid[top[u]], tid[u], 0, k);
            i = 0;
            u = fa[top[u]];
        }
    }
    int f = 1;
    if (tid[u] > tid[v]) swap(u, v), f = 0;
    if (i < 0) tm = query(1, 1, dfn, tid[u], tid[v], f, k);
    else tm = tm+query(1, 1, dfn, tid[u], tid[v], f, k); 
    for (i = V.size()-1;i >= 0;i--) {
        tm = tm+V[i];
    }
    re = max(re, tm.re);
    printf("%d\n", re);
}

inline int in() {
    char c;
    int re = 0;
    c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        re = re*10+c-'0';
        c = getchar();
    }
    return re;
}

int main() {
    int T, i, j, u, v, n, m, d;
    T = in();
    while (T--) {
        n = in();//scanf("%d", &n);
        init();
        for (i = 1;i <= n;i++) val[i] = in();//scanf("%d", &val[i]);
        for (i = 1;i < n;i++) {
            u = in(), v = in();//scanf("%d%d", &u, &v);
            add(u, v), add(v, u);
        }
        dfn = 0;
        dfs(1, 0);
        dfs1(1, 0, 1, 1);
        build(1, 1, n);
        m = in();//scanf("%d", &m);
        while (m--) {
            u = in(), v = in(), d = in();//'scanf("%d%d%d", &u, &v, &d);
            solve(u, v, d);
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值