题目链接
题目大意:给你一颗树,再给定m条路径,你可以使树上一条边的权值变为0,要求这m条路径的最大值最小。
很暴力的想法就是枚举n-1条边挨个删,这样是超时的。
但是看到最大值最小,很容易想到二分答案,然后开始去思考这个最小值是否满足单调性。
很明显,如果完成这m个任务需要a的时间,那么必然存在一个b使得b>a,并且可以用b时间去完成这m个任务。
然后就可以直接去二分这个最小值了,考虑怎么判断答案的正确性。
我们注意到,如果这m条路径中有k条的值是大于我们二分的这个mid的,那么我们归零的这条边必须被这k条边经过,并且归零之后满足所有路径长度小于mid。若不被k条边经过的话,那么我们去掉的边至少有一条路径的长度是没有变化的,依旧是大于mid,所以要求被这k条边经过。
然后考虑怎么快速的修改边被覆盖的次数,树上差分,然后注意到这里修改的是边的覆盖次数,所以我们把边权下放给子结点,然后树剖就可以了,当然也可以倍增,但常数有点大,树剖的话我们可以很自然的利用dfs序去干一些事情。
代码:
#include<bits/stdc++.h>
#define lk (k<<1)
#define rk (k<<1|1)
using namespace std;
typedef long long ll;
const double EPS=1e-8;
const double PI=acos(-1.0);
const int INF=0x3f3f3f3f;
const int N=3e5+10;
inline int read()
{
char c;
int sign=1,res=0;
c=getchar();
while(c<'0'||c>'9'){
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
res=res*10+c-'0';
c=getchar();
}
return sign*res;
}struct edge
{
int v,next,w;
}e[N<<1];
int head[N],cnt;
void add(int u,int v,int w)
{
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}
int n,m;
void init()
{
n=read();
m=read();
for(int i=1;i<n;i++){
int u,v,w;
u=read();
v=read();
w=read();
add(u,v,w);
add(v,u,w);
}
}
int top[N],dfn[N],len,dis[N],l[N],id[N];
int fa[N],dep[N],size[N],son[N];
void dfs1(int u,int p)
{
dep[u]=dep[p]+1;
son[u]=0;
size[u]=1;
fa[u]=p;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==p) continue;
dis[v]+=dis[u]+e[i].w;
l[v]=e[i].w;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
void dfs2(int u,int p)
{
dfn[u]=++len;
id[len]=u;
if(son[u])
{
top[son[u]]=top[u];
dfs2(son[u],u);
}
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==p) continue;
if(!top[v])
{
top[v]=v;
dfs2(v,u);
}
}
}
int lca(int u,int v)
{
int fu=top[u],fv=top[v];
while(fu!=fv)
{
if(dep[fu]<dep[fv]) swap(fu,fv),swap(u,v);
u=fa[fu];fu=top[u];
}
if(dep[u]>dep[v]) swap(u,v);
return u;
}
int x[N],y[N],val[N],cf[N],z[N],maxw;
bool judge(int mid)
{
memset(cf,0,sizeof(cf));
int k=0;
for(int i=1;i<=m;i++)
{
if(val[i]>mid)
{
cf[x[i]]++;
cf[y[i]]++;
cf[z[i]]-=2;
k++;
}
}
for(int i=n;i>=1;i--)
{
cf[fa[id[i]]]+=cf[id[i]];
if(cf[id[i]]==k&&maxw-l[id[i]]<=mid) return true;
}
return false;
}
int main()
{
init();
dfs1(1,0);
top[1]=1;
dfs2(1,0);
int r=-1,l=0;
for(int i=1;i<=m;i++)
{
x[i]=read();
y[i]=read();
z[i]=lca(x[i],y[i]);
val[i]=dis[x[i]]+dis[y[i]]-2*dis[z[i]];
maxw=max(maxw,val[i]);
}
r=maxw;
int ans,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(judge(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}