bzoj 4326 运输计划 (树链剖分 + 树上差分 + 二分)

来源:互联网 发布:网络小胖的电视 编辑:程序博客网 时间:2024/09/21 09:28

不想贴题面系列……
这道题就是先二分一个答案,然后check,如果路线的总长度比二分的答案大,就把它们拎出来进行树上差分(求它们所有路线都经过的边),然后把这条边的权值减掉(贪心),反复check即可。

#include <bits/stdc++.h>using namespace std;const int N = 300010;int n, m;struct E {    int v, w, next;} e[N << 1];int num = 0, head[N << 1];void add(int u, int v, int w) {    e[++ num].v = v; e[num].w = w;    e[num].next = head[u]; head[u] = num;}struct Node {    int s, t, len, lca;} car[N];int fa[N], son[N], siz[N], dep[N], dis[N], top[N];void dfs1(int u, int f, int d) {    siz[u] = 1; fa[u] = f; dep[u] = d;     for(int i = head[u]; i; i = e[i].next) {        int v = e[i].v;        if(v == f) continue;        dis[v] = dis[u] + e[i].w;        dfs1(v, u, d + 1);        siz[u] += siz[v];        if(siz[son[u]] < siz[v])            son[u] = v;    }}void dfs2(int u, int tp) {    top[u] = tp;    if(! son[u]) return ;    dfs2(son[u], tp);    for(int i = head[u]; i; i = e[i].next) {        int v = e[i].v;        if(v == fa[u] || v == son[u]) continue;        dfs2(v, v);    }}int getlca(int u, int v) {    int fu = top[u], fv = top[v];    while(fu != fv) {        if(dep[fu] < dep[fv]) swap(fu, fv), swap(u, v);        u = fa[fu], fu = top[u];    }    if(dep[u] > dep[v]) swap(u, v);    return u;}int tot, delta, mmax, flag[N];void dfs(int u, int W) {    for(int i = head[u]; i; i = e[i].next) {        int v = e[i].v;        if(v == fa[u]) continue ;         dfs(v, e[i].w);        flag[u] += flag[v];    }    if(flag[u] == tot) delta = max(W, delta);}bool check(int mid) {    tot = delta = mmax = 0;    memset(flag, 0, sizeof(flag));    for(register int i = 1; i <= m; ++ i)        if(car[i].len > mid) {            ++ tot; mmax = max(mmax, car[i].len - mid);            flag[car[i].s] ++, flag[car[i].t] ++, flag[car[i].lca] -= 2;        }    dfs(1, 0);    if(mmax - delta > 0) return 0;    return 1;}int main() {    scanf("%d %d", &n, &m);    for(register int i = 1; i < n; ++ i) {        int u, v, w;        scanf("%d %d %d", &u, &v, &w);        add(u, v, w); add(v, u, w);    }    dfs1(1, 0, 1); dfs2(1, 1); int l = 0, r = 0;    for(register int i = 1; i <= m; i ++) {        scanf("%d %d", &car[i].s, &car[i].t);        car[i].lca = getlca(car[i].s, car[i].t);        car[i].len = dis[car[i].s] + dis[car[i].t] - 2 * dis[car[i].lca];        r = max(r, car[i].len);    }    while(l < r) {        int mid = (l + r) >> 1;        if(check(mid)) r = mid;        else l = mid + 1;    }    printf("%d\n", l);    return 0;}
阅读全文
0 0
原创粉丝点击