[ybtoj 4.5.5/P2680] 运输计划 [LCA/二分]
题意
一棵树,有 
    
     
      
       
        N
       
      
      
       N
      
     
    N 个点,有边权
 给你 
    
     
      
       
        M
       
      
      
       M
      
     
    M 条路径,每条路径的权值等于在这条路径上的所有边的边权之和
 求在将一条边的边权改成 
    
     
      
       
        0
       
      
      
       0
      
     
    0 的情况下,所有的路径的权值的最大值最小
思路
在看到这种“最大值最小的”题目时,有一个常见的思路就是二分
考虑直接二分答案
然后就可以得到一个很显然的结论
一个答案是合法的,当且仅当所有权值比答案大的路径都经过同一条边且所有的路径,且这些路径减去这条边的权值都比答案小
然后就可以把这道题的判断改为判定如上条件了
在判定每一条边被路径经过的次数时候可以利用树上差分的方法
就差不多结束了
代码
#include<bits/stdc++.h>
#define N 300010
using namespace std;
struct qq{
	int to,from,next,dis;
}a[N*2];
struct pp{
	int x,y,lca,dis;
}b[N];
int f[N][20],dis[N],dep[N],s[N],head[N],n,m,tot,ans;
void add(int x,int y,int z){a[++tot].to=y;a[tot].from=x;a[tot].dis=z;a[tot].next=head[x];head[x]=tot;}
bool o(pp x,pp y){return x.dis>y.dis;}
void dfs(int x,int fa,int dist)
{
	f[x][0]=fa;dep[x]=dep[fa]+1;dis[x]=dis[fa]+dist;
	for(int i=1;i<=18;i++)f[x][i]=f[f[x][i-1]][i-1];
	for(int i=head[x];i;i=a[i].next)
		if(a[i].to!=fa)dfs(a[i].to,x,a[i].dis);
}
void dfs(int x,int fa)
{
	for(int i=head[x];i;i=a[i].next)
		if(a[i].to!=fa)dfs(a[i].to,x),s[x]+=s[a[i].to];
}
int lca(int x,int y)
{
	if(dep[x]<dep[y])x^=y^=x^=y;
	for(int i=19;i>=0;i--)
		if(dep[f[x][i]]>=dep[y])x=f[x][i];
	if(x==y)return x;
	for(int i=19;i>=0;i--)
		if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	return f[x][0];
}
bool check(int mid)
{
	int x=0,mx=0;
	for(int i=1;i<=n;i++)s[i]=0;
	for(int i=1;i<=m&&b[i].dis>mid;i++)
		s[b[i].x]++,s[b[i].y]++,s[b[i].lca]--,s[f[b[i].lca][0]]--,x=i;
	dfs(1,0);
	for(int i=1;i<2*n;i+=2)
		if(s[a[i].to]==x&&s[a[i].from]==x)mx=max(mx,a[i].dis);
	return b[1].dis<=mid+mx;
}
int main()
{
	int x,y,z,l=0,r=0,mid;
	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,0);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		b[i].x=x;b[i].y=y;b[i].lca=lca(x,y);
		b[i].dis=dis[x]+dis[y]-2*dis[b[i].lca];
	}
	sort(b+1,b+m+1,o);
	r=b[1].dis;
	while(l<=r)
	{
		mid=l+r>>1;
		if(check(mid))ans=mid,r=mid-1;
		else l=mid+1;
	}
	cout<<ans;
}
                

                
            
        
浙公网安备 33010602011771号