luogu P2680 运输计划

传送门

要最长链的长度最短,一秒想到二分,因为如果对于某个长度满足改掉一边的边权后能使得所有链长度不超过该长度,则所有比他长的长度也满足.

二分最终答案.我们要使得原来长度大于二分的(mid)的链删边后小于(mid),所以要找出一条最长的,被所有长度大于(mid)的链包含的边,使得最长链长度减去这条边长度不超过(mid)

用树剖求出(lca),用来求每条链的长度.我们还要在check的时候知道每条边被哪些长度大于(mid)的链覆盖,使用差分即可

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define max(a,b) ((a)>(b)?(a):(b))

using namespace std;
const int N=300000+10;
il LL rd()
{
    re LL x=0,w=1;re char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int to[N<<2],nt[N<<2],w[N<<2],hd[N],tot=1;
il void add(int x,int y,int z)
{
  ++tot;to[tot]=y;nt[tot]=hd[x];w[tot]=z;hd[x]=tot;
  ++tot;to[tot]=x;nt[tot]=hd[y];w[tot]=z;hd[y]=tot;
}
int n,sz[N],de[N],hc[N],top[N],dis[N],fae[N],fa[N],a[N],m,q[N][3],len[N],maxl,ma,nm;
il void dfs1(int x,int ffa)
{
  sz[x]=1;
  for(re int i=hd[x];i;i=nt[i])
    {
      int y=to[i];
      if(y==ffa) continue;
      dis[y]=dis[x]+w[i],de[y]=de[x]+1,fae[y]=w[i],fa[y]=x;
      dfs1(y,x);
      sz[x]+=sz[y];
      if(sz[y]>sz[hc[x]]) hc[x]=y;
    }
}
il void dfs2(int x,int ffa)
{
  if(hc[x])
    {
      top[hc[x]]=top[x];
      dfs2(hc[x],x);
    }
  for(re int i=hd[x];i;i=nt[i])
    {
      int y=to[i];
      if(y==ffa||y==hc[x]) continue;
      top[y]=y;
      dfs2(y,x);
    }
}
il void dd(int x,int ffa)
{
  for(re int i=hd[x];i;i=nt[i])
    {
      int y=to[i];
      if(y==ffa) continue;
      dd(y,x);
      a[x]+=a[y];
      if(a[y]>=nm) ma=max(ma,fae[y]);
    }
}
il bool check(int mid)
{
  ma=nm=0;
  for(re int i=1;i<=n;i++) a[i]=0;
  for(re int i=1;i<=m;i++)
    if(len[i]>mid) ++a[q[i][0]],++a[q[i][1]],----a[q[i][2]],++nm;
  dd(1,0);
  return mid>=maxl-ma;
}

int main()
{
  n=rd(),m=rd();
  for(re int i=1;i<n;i++)
    {
      int x=rd(),y=rd(),z=rd();
      add(x,y,z);
    }
  de[1]=1,dfs1(1,0),top[1]=1,dfs2(1,0);
  for(re int i=1;i<=m;i++)
    {
      int x=q[i][0]=rd(),y=q[i][1]=rd();
      while(top[x]!=top[y])
    	{
    	  if(de[top[x]]<de[top[y]]) swap(x,y);
    	  len[i]+=dis[x]-dis[top[x]]+fae[top[x]];
    	  x=fa[top[x]];
    	}
      if(de[x]<de[y]) swap(x,y);
      len[i]+=dis[x]-dis[y];
      q[i][2]=y;
      maxl=max(maxl,len[i]);
    }
  int l=0,r=maxl,mid,ans=maxl;
  while(l<=r)
    {
      mid=(l+r)>>1;
      if(check(mid)) r=mid-1,ans=mid;
      else l=mid+1;
    }
  printf("%d
",ans);
  return 0;
}

原文地址:https://www.cnblogs.com/smyjr/p/9608284.html