【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;
}