1. 程式人生 > 其它 >【YBTOJ】【Luogu P2680】[NOIP2015 提高組] 運輸計劃

【YBTOJ】【Luogu P2680】[NOIP2015 提高組] 運輸計劃

【YBTOJ】【Luogu P2680】[NOIP2015 提高組] 運輸計劃:

連結:

洛谷

題目大意:

在一棵 \(n\) 個節點的樹中,給定 \(m\) 條路徑,現在能把樹中某邊邊權改為零,求最大路徑邊權和最小值。

正文:

“求最大路徑邊權和最小值”可以聯絡到二分答案,二分最大路徑邊權和。在二分的過程中,一些路徑邊權和要大於二分值,我們叫它們非法路徑,就要在這些路徑中找出一條它們共同覆蓋的邊,且邊權最大。那麼可以通過確定最大的非法路徑減去我們要找的最大的邊與二分值的大小關係確定二分範圍。

接下來的目標就是找邊。根據邊的條件,它需要被覆蓋於所有非法路徑,那麼通過樹上差分記錄每條邊被經過的次數。在被經過次數等於非法路徑數的邊中,找個邊權最大的就是了。

程式碼:

const int N = 300010;

inline ll Read()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

// main
int n, m, logN;
ll ans;
struct Question
{
	ll x, y, lca, dis;
	bool operator < (Question &a) const
	{
		return dis > a.dis;
	}
}Q[N];

// edge
struct edge
{
	int from, to, val, nxt;
}e[N << 1];
int head[N], tot;

void add(int u, int v, int w)
{
	e[++tot] = (edge) {u, v, w, head[u]}, head[u] = tot;
	e[++tot] = (edge) {v, u, w, head[v]}, head[v] = tot;
}

// LCA
ll dis[N];
bool vis[N];
int dep[N], f[N][30], fa[N];
queue <int> q;

void bfs(int root)
{
	for(; !q.empty(); q.pop());
	q.push(root);
	dep[root] = 1;
	while(!q.empty())
	{
		int u = q.front(); q.pop();
		vis[u] = 1;
		for (int v, i = head[u]; i; i = e[i].nxt)
		{
			if (vis[v = e[i].to]) continue;
			fa[v] = u;
			dep[v] = dep[u] + 1;
			dis[v] = dis[u] + e[i].val;
			f[v][0] = u;
			for (int j = 1; j <= logN; j++)
				f[v][j] = f[f[v][j - 1]][j - 1];
			q.push(v);
		} 
	}
}

int LCA(int u, int v)
{
	if (dep[u] > dep[v]) u ^= v ^= u ^= v;
	for (int j = logN; ~j; j--)
		if (dep[f[v][j]] >= dep[u]) 
			v = f[v][j];
	if(u == v) return u;
	for (int j = logN; ~j; j--)
		if (f[v][j] != f[u][j]) 
			u = f[u][j], v = f[v][j];
	return f[u][0];
}

// binary - check
int val[N];
void dfs(int u, int fa)
{
	for (int v, i = head[u]; i; i = e[i].nxt)
	{
		if ((v = e[i].to) == fa) continue;
		dfs(v, u);
		val[u] += val[v];
	}
}

bool check(ll x)
{
	memset (val, 0, sizeof val);
	int num = 0;
	for (int i = 1; i <= m; i++)
	{
		if (Q[i].dis <= x) break;
		val[Q[i].x] ++, val[Q[i].lca] --;
		val[Q[i].y] ++, val[Q[i].lca] --;
		num++;
	}
	dfs(1, 0);
	ll Max = 0;
	for (int i = 1; i <= n; i++)
		if(val[i] == num) Max = max(Max, dis[i] - dis[fa[i]]);
	return Q[1].dis - Max > x;
}

ll l, r, mid;
// main()-
int main()
{
	n = Read(), m = Read(); logN = log2(n) + 1;
	for (ll u, v, w, i = 1; i < n; i++)
		u = Read(), v = Read(), w = Read(), 
		add(u, v, w), l = max(l, w);
	bfs(1);
	for (int i = 1, u, v, c; i <= m; i++)
		u = Read(), v = Read(),
		Q[i] = (Question){u, v, c = LCA(u, v), dis[u] + dis[v] - 2 * dis[c]},
		r = max(r, Q[i].dis);
	sort (Q + 1, Q + 1 + m);
	l = r - l;
	while (l <= r) 
	{
		mid = l + r >> 1;
		if (check(mid)) l = mid + 1;
		else ans = mid, r = mid - 1;
	}
	
	printf ("%lld\n", ans);
	return 0;
}