题目传送门
题目大意:
有一颗n个节点的树和m条路径,你可以将树上任一条边的长度变为0,求所有路径中最长的一条的最小值。
思考过程:
这是典型的求最大值最小可以为多少的问题,我们考虑二分答案。
然后我们考虑如何检验当前答案是否可行。显然,长度小于当前答案的路径都是可行的,问题转化为如何判断长度大于当前答案的路径是否可行。因为我们要删掉一条边使得这些路径长度都变小,所以我们肯定要删掉这些路径的交,而且要删掉交里面长度最大的那条边。而这可以用差分来解决。
具体做法:
我们对于每条长度超过当前答案的路径的两个端点(假设为x,y)求lca,然后book[x]++,book[y]++,book[lca]-=2。在按dfs序从后往前把儿子的book加到父亲上,最后book值等于超过当前答案路径的条数的就是要检验的,求他们的最大值就好。如果最大值大于等于原最长路径长度-当前答案,则当前答案可行。
代码:
#include
using namespace std;
const int maxn=3e5+1000;
struct stu
{
int to,next,dis;
}road[maxn*2]; int first[maxn],cnt;
int dep[maxn],cnum[maxn],fa[maxn],val[maxn],hson[maxn],top[maxn],id[maxn],dfn[maxn],book[maxn];
int u[maxn],v[maxn],len[maxn];
int nowtop,n,maxx,ans,mid,m;
void addedge(int x,int y,int dis1)
{
road[++cnt].to=y;
road[cnt].next=first[x];
first[x]=cnt;
road[cnt].dis=dis1;
}
void dfs1(int now,int depth)
{
int max1=0;
dep[now]=depth;
cnum[now]=1;
for(int i=first[now];i;i=road[i].next)
{
int to=road[i].to;
if(to==fa[now]) continue;
fa[to]=now;
val[to]=road[i].dis;
dfs1(to,depth+1);
cnum[now]+=cnum[to];
if(cnum[to]>max1) { hson[now]=to;max1=cnum[to]; }
}
}
void dfs2(int now,int what)
{
if(what==1) nowtop=now;
top[now]=nowtop;
id[now]=++cnt;
dfn[cnt]=now;
if(!hson[now]) return;
dfs2(hson[now],0);
for(int i=first[now];i;i=road[i].next)
{
int to=road[i].to;
if(to==fa[now]||to==hson[now]) continue;
dfs2(to,1);
}
}
int get_lca(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
return y;
}
struct seg1
{
int seg[maxn*5];
void build(int note,int l,int r)
{
if(l>r) return;
if(l==r) { seg[note]=val[dfn[l]];return; }
int mid=(l+r)>>1;
build(note*2,l,mid);build(note*2+1,mid+1,r);
seg[note]=seg[note*2]+seg[note*2+1];
}
int query(int note,int l,int r,int wantl,int wantr)
{
if(l>wantr||r<wantl) return 0;
if(l>=wantl&&r<=wantr) return seg[note];
int mid=(l+r)>>1;
return query(note*2,l,mid,wantl,wantr)+query(note*2+1,mid+1,r,wantl,wantr);
}
int get_ans(int x,int y)
{
int nowans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
nowans+=query(1,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
nowans+=query(1,1,n,id[y],id[x]);
nowans-=val[y];
return nowans;
}
}T1;
void work(int x,int y)
{
int lca1=get_lca(x,y);
book[x]++;book[y]++;book[lca1]-=2;
}
bool judge()
{
if(maxx<=mid) return 1;
memset(book,0,sizeof(book));
int cntt=0,want=maxx-mid;
for(int i=1;i<=m;i++)
{
if(len[i]>mid)
{
cntt++;
work(u[i],v[i]);
}
}
for(int i=n;i>=1;i--) book[fa[dfn[i]]]+=book[dfn[i]];
int nowmax=0;
for(int i=1;i<=n;i++)
if(book[i]>=cntt) nowmax=max(nowmax,val[i]);
if(nowmax>=want) return 1;
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n-1;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);addedge(y,x,z);
}
dfs1(1,1);
cnt=0;
dfs2(1,1);
T1.build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u[i],&v[i]);
if(dep[u[i]]<dep[v[i]]) swap(u[i],v[i]);
len[i]=T1.get_ans(u[i],v[i]);
ans=max(ans,len[i]);
maxx=ans;
}
int l=0,r=ans;
while(l<=r)
{
mid=(l+r)>>1;
bool kk=judge();
if(kk) { ans=mid;r=mid-1; }
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}