bzoj 4326 运输计划

二分答案 + 树上差分.

首先可以考虑二分答案,变为判定是否存在合法方案使得改造后给出的路径长度都不超过 $mid$ .

预处理每条路径的长度 $len$ ,若 $len\le mid$ ,则不用考虑.否则,被改造的边长度至少为 $mid-len$ .

将每条路径按上述过程处理,可以得出被改造的边长度至少为 $\max (mid-len_i)$ ,并且在所有需要考虑的路径上.

用树上差分给路径上的边打上标记,然后枚举每条边进行验证.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
int out=0,sgn=1;
char jp=getchar();
while(jp!='-' && (jp<'0' || jp>'9'))
jp=getchar();
if(jp=='-')
sgn=-1,jp=getchar();
while(jp>='0' && jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*sgn;
}
const int MAXN=3e5+10;
int ecnt=0,head[MAXN],to[MAXN<<1],nx[MAXN<<1],val[MAXN<<1];
void addedge(int u,int v,int w)
{
++ecnt;
to[ecnt]=v;
nx[ecnt]=head[u];
val[ecnt]=w;
head[u]=ecnt;
}
int n,m,x[MAXN],y[MAXN],z[MAXN],len[MAXN];
int tofa[MAXN],dis[MAXN],mx=0;
int dep[MAXN],Log[MAXN],fa[MAXN][20];
int LCA(int x,int y)
{
if(dep[x]<dep[y])
swap(x,y);
for(int i=Log[dep[x]-dep[y]];i>=0;--i)
if(dep[x]-dep[y]>=(1<<i))
x=fa[x][i];
if(x==y)
return x;
for(int i=Log[dep[x]];i>=0;--i)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void dfs_pre(int u,int F)
{
fa[u][0]=F;
for(int i=1;(1<<i)<=dep[u];++i)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v==F)
continue;
dep[v]=dep[u]+1;
dis[v]=dis[u]+val[i];
tofa[v]=val[i];
dfs_pre(v,u);
}
}
int dif[MAXN],tot,lim;
bool dfs_calc(int u,int F)
{
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v==F)
continue;
if(dfs_calc(v,u))
return true;
dif[u]+=dif[v];
}
if(u!=1 && dif[u]==tot && tofa[u]>=lim)
return true;
return false;
}
bool check(int mid)
{
tot=0,lim=0;
for(int i=1;i<=n;++i)
dif[i]=0;
for(int i=1;i<=m;++i)
{
if(len[i]<=mid)
continue;
lim=max(lim,len[i]-mid);
++tot;
++dif[x[i]],++dif[y[i]];
dif[z[i]]-=2;
}
if(!tot)
return true;
return dfs_calc(1,0);
}
int main()
{
n=read(),m=read();
Log[0]=-1,Log[1]=0;
for(int i=2;i<=n;++i)
Log[i]=Log[i>>1]+1;
for(int i=1;i<n;++i)
{
int u=read(),v=read(),w=read();
addedge(u,v,w);
addedge(v,u,w);
}
for(int i=1;i<=m;++i)
{
x[i]=read();
y[i]=read();
}
dfs_pre(1,0);
for(int i=1;i<=m;++i)
{
z[i]=LCA(x[i],y[i]);
len[i]=dis[x[i]]+dis[y[i]]-2*dis[z[i]];
mx=max(mx,len[i]);
}
int L=0,R=mx,ans;
while(L<=R)
{
int mid=(L+R)>>1;
if(check(mid))
ans=mid,R=mid-1;
else
L=mid+1;
}
cout<<ans<<endl;
return 0;
}