洛谷 P2680

题目链接:P2680 运输计划

题目大意

题目要求的是我们找一条边,可以让这条边的权值变成0,然后给了你几对点,让你求在改变边的权值之后的最大值,然后输出最小的最大值

solution

最小值最大? 二分答案.

那我们可以用LCA+树上差分来做(就这样不想写了)

code:

/**
*    Author: Alieme
*    Data: 2020.8.26
*    Problem: Luogu P2680
*    Time: O()
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>

#define int long long
#define rr register

#define inf 1e9
#define MAXN 1000010

using namespace std;

inline int read() {
	int s = 0, f = 0;
	char ch = getchar();
	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
	return f ? -s : s;
}

void print(int x) {
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) print(x / 10);
	putchar(x % 10 + 48);
}

struct Node {
	int u;
	int v;
	int lca;
	int diss;
}lu[MAXN];

struct Edge {
	int nxt;
	int to;
	int val;
	Edge() {}
	Edge(int Nxt, int To, int Val) {nxt = Nxt, to = To, val = Val;}
}e[MAXN];

int tot, n, m, cnt;

int head[MAXN], dep[MAXN], dis[MAXN], temp[MAXN], num[MAXN];

int fa[MAXN][30];

inline void add(int from, int to, int val) {
	e[++tot] = Edge(head[from], to, val);
	head[from] = tot;
}

void dfs(int x, int fath) {
	num[++cnt] = x;
	dep[x] = dep[fath] + 1;
	fa[x][0] = fath;
	for (rr int i = 1; i < 25; i++)  fa[x][i] = fa[fa[x][i - 1]][i - 1];
	for (rr int i = head[x]; i; i = e[i].nxt) {
		int to = e[i].to;
		if (to == fath) continue;
		dis[to] = dis[x] + e[i].val;
		dfs(to, x);
	}
}

inline int LCA(int x, int y) {
	if (dep[x] < dep[y]) swap(x, y);
	int t = dep[x] - dep[y];
	for (rr int i = 0; i < 25; i++)
		if ((1 << i) & t)
			x = fa[x][i];
	if (x == y) return x;
	for (rr int i = 24; i >= 0; i--) 
		if (fa[x][i] != fa[y][i])
			x = fa[x][i], y = fa[y][i];
	return fa[x][0];
}

inline bool check(int x) {
	int cnt = 0, ans = 0;
	memset(temp, 0, sizeof temp);
	for (rr int i = 1; i <= m; i++) 
		if (lu[i].diss > x) {
			temp[lu[i].u]++;
			temp[lu[i].v]++;
			temp[lu[i].lca] -= 2;
			ans = max(ans, lu[i].diss - x);
			cnt++;
		}
	if (cnt == 0) return true;
	for (rr int i = n; i >= 1; i--) temp[fa[num[i]][0]] += temp[num[i]];
	for (rr int i = 2; i <= n; i++) if (temp[i] == cnt && dis[i] - dis[fa[i][0]] >= ans) return true;
	return false;
}

signed main() {
	n = read();
	m = read();
	for (rr int i = 1; i < n; i++) {
		int u = read();
		int v = read();
		int w = read();
		add(u, v, w);
		add(v, u, w);
	}
	dis[1] = 0;
	dfs(1, 0);
	for (rr int i = 1; i <= m; i++) {
		lu[i].u = read();
		lu[i].v = read();
		lu[i].lca = LCA(lu[i].u, lu[i].v);
		lu[i].diss = dis[lu[i].u] + dis[lu[i].v] - 2 * dis[lu[i].lca];
	}
	int l = 0, r = inf;
	while (l < r) {
		int mid = (l + r) >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}
	print(l);
}
posted @ 2020-08-30 07:38  Aliemo  阅读(109)  评论(1编辑  收藏  举报