题目
思路
一个带边权LCA+二分答案(check使用树上差分)
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
using namespace std;
int fa[500010][27],head[500010],c[500010],cf[500010],v[500010][27],x,y,z;
struct f{
int s,to,net,w;
} a[1000020];
struct fP{
int x,y,w,lca;
} uo[500010];
bool cmp(fP a,fP b)
{
return a.w>b.w;
}
int n,m,ans;
void dfs(int x,int f)
{
fa[x][0]=f;
c[x]=c[f]+1;
for (int j=1;(1<<j)<=c[x];j++)
{
fa[x][j]=fa[fa[x][j-1]][j-1];
v[x][j]=v[x][j-1]+v[fa[x][j-1]][j-1];
}
for (int i=head[x];i;i=a[i].net)
{
if (a[i].to!=f) v[a[i].to][0]=a[i].w,dfs(a[i].to,x);
}
return;
}
int k=1;
void add(int u,int v,int w)
{
a[k].s=u;
a[k].w=w;
a[k].to=v;
a[k].net=head[u];
head[u]=k++;
return;
}
int vv;
int LCA(int x,int y)
{
if (c[x]>c[y]) swap(x,y);
vv=0;
for (int i=20;i>=0;i--)
{
if (c[x]<=c[fa[y][i]]) vv+=v[y][i],y=fa[y][i];
}
if (x==y) return x;
for (int i=20;i>=0;i--)
{
if (fa[x][i]==fa[y][i]) continue;
else vv+=v[x][i]+v[y][i],x=fa[x][i],y=fa[y][i];
}
vv+=v[x][0]+v[y][0];
return fa[x][0];
}
void dfs1(int x,int f)
{
for (int i=head[x];i;i=a[i].net)
{
if (a[i].to!=f)
{
dfs1(a[i].to,x);
cf[x]+=cf[a[i].to];
}
}
return;
}
bool check(int mid)
{
memset(cf,0,sizeof(cf));
int i=1,mx=-1;
for (;i<=m&&uo[i].w>mid;i++)
{
cf[uo[i].x]++;
cf[uo[i].y]++;
cf[uo[i].lca]--;
cf[fa[uo[i].lca][0]]--;
}
i--;
dfs1(1,0);
for (int j=1;j<2*n;j++) if (cf[a[j].s]==cf[a[j].to]&&cf[a[j].to]==i) mx=max(mx,a[j].w);
return uo[1].w-mx<=mid;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dfs(1,0);
int l=0,r;
for (int i=1;i<=m;i++)
{
scanf("%d%d",&uo[i].x,&uo[i].y);
uo[i].lca=LCA(uo[i].x,uo[i].y);
uo[i].w=vv;
}
sort(uo+1,uo+1+m,cmp);
r=uo[1].w;
ans=r;
r--;
int mid;
while (l<=r)
{
mid=(l+r)>>1;
if (check(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans;
return 0;
}