#### awa

admin 2020-07-31 8:49:17 2020-07-31 8:49:29

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e6+10;

int n,m;
//存图 
int head[N],to[N<<1],e[N<<1],nxt[N<<1],tot;

//lca
int deep[N],f[N][20];
int seq[N],dist[N],cnt;//seq[]存储dfs的顺序,dist[x]表示x到根的距离

//差分数组
int sum[N]; 

struct Path
{
	int a,b;//路径的端点 
	int lca,dist;//a 和 b的最近公共祖先,路径长度 
}path[N];  

void add(int a,int b,int c)
{
	to[++tot]=b;
	e[tot]=c;
	nxt[tot]=head[a];
	head[a]=tot;
}

void dfs(int x)
{
	seq[++cnt]=x;
	for(int i=1;i<20;i++)
	{
		f[x][i]=f[f[x][i-1]][i-1];
	}
	
	for(int i=head[x];i;i=nxt[i])
	{
		int y=to[i],w=e[i];
		if(f[x][0]==y) continue;
		deep[y]=deep[x]+1;
		dist[y]=dist[x]+w;
		f[y][0]=x;
		dfs(y);
	}
}

int lca(int x,int y)
{
	//先跳y 
	if(deep[x]>deep[y]) swap(x,y);
	
	for(int i=19;i>=0;i--)
	{
		if(deep[f[y][i]]>=deep[x])
			y=f[y][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];
}

//当能找到一个公共边删除后,使得所有路径都小于等于mid 
bool check(int mid)
{
	memset(sum,0,sizeof(sum));
	int cnt=0,maxd=0;//cnt表示路径种大于mid的数量,maxd大于mid的路径的最大值
	for(int i=1;i<=m;i++)
	{
		if(path[i].dist>mid)
		{
			cnt++;
			maxd=max(maxd,path[i].dist);
			sum[path[i].a]++,sum[path[i].b]++;
			sum[path[i].lca]-=2;
		}
	} 
	if(cnt==0) return true;//没有任何一条边大于mid 
	
	//利用刚刚记录的dfs序列计算差分的和
	for(int i=n;i;i--)
		sum[f[seq[i]][0]]+=sum[seq[i]];
	
	for(int i=1;i<=n;i++)
	{
		//当这条边时公共边,同时这条边的距离大于 
		int w=dist[i]-dist[f[i][0]];
		if(sum[i]==cnt && maxd-w<=mid)
			return true;
	} 
	return false;
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n-1;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c),add(b,a,c);
	} 
	
	deep[1]=1;
	dfs(1);
	
	for(int i=1;i<=m;i++)
	{
		int a,b;
		cin>>a>>b;
		int p=lca(a,b);
		path[i]=(Path){a,b,p,dist[a]+dist[b]-dist[p]*2};	
	}
	
	int l=0,r=1e9;
	while(l<r)
	{
		int mid=(l+r)>>1;
		
		if(check(mid))//当check为true说明mid取大了 
			r=mid;
		else//否则说明取小了 
			l=mid+1;
			
	}
	cout<<r;
	return 0;
} 

共 2 条回复

Laffey

%%%(

xy0313

%%%