您的位置:首页 > 其它

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

2017-10-26 10:37 441 查看
不想贴题面系列……

这道题就是先二分一个答案,然后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
;

int fa
, son
, siz
, dep
, dis
, top
;
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),
b5b3
swap(u, v);
u = fa[fu], fu = top[u];
}
if(dep[u] > dep[v]) swap(u, v);
return u;
}

int tot, delta, mmax, flag
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: