P2680 [NOIP2015 提高组] 运输计划

题目

题目

思路

一个带边权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;
}

猜你喜欢

转载自blog.csdn.net/weixin_49843717/article/details/115253154