P4886 快递员
0x01 题意
给定一棵树和树上若干个点对,选出一个点(x)最小化(max_{1leq ileq m}(dis(u_i,x)+dis(v_i,s)))
0x02 解
我们先随便选取一个点,找到所有使得题给式子值最大的点对;
接着有三种情况:
- 若该点在任意一个找到的点对的最短路径上,那么答案不能更优,输出该点
- 若找出的点对中任意两个点对在该点的子树中且不在同一子树中,那么答案不能更优,输出该点
- 若不满足以上两条,找到该点的子树中唯一有点对的那棵,取它的重心作为新的点进行递归
最后能够找到答案
0x03 码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=500010;
int n,m,e[N],ne[N],w[N],idx,h[N],sum,siz[N],maxp[N],u[N],v[N],rt,sub[N],dist[N],que[N],ans=1e9;
bool vis[N];
inline void add(int a,int b,int c){
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void groot(int now,int fa){//找重心
siz[now]=1,maxp[now]=0;
for(int i=h[now];~i;i=ne[i]){
int j=e[i];
if(vis[j]||j==fa) continue;
groot(j,now);siz[now]+=siz[j];
if(siz[j]>maxp[now]) maxp[now]=siz[j];
}
if(sum-siz[now]>maxp[now]) maxp[now]=sum-siz[now];
if(maxp[now]<maxp[rt]) rt=now;
}
void gdist(int now,int fa,int st){//找到st结点的距离
sub[now]=st;
for(int i=h[now];~i;i=ne[i]){
int j=e[i];
if(j!=fa) dist[j]=dist[now]+w[i],gdist(j,now,st);
}
}
void solve(int now){
if(vis[now]){printf("%d
",ans);exit(0);}
vis[now]=1,dist[now]=0;
for(int i=h[now];~i;i=ne[i]){//预处理与now结点的距离
int j=e[i];
dist[j]=w[i];
gdist(j,now,j);
}
int maxx=0,len=0,las=0;
for(int i=1;i<=m;i++){
if(dist[u[i]]+dist[v[i]]>maxx){//找与点对的最大距离
len=1;
que[len]=i;
maxx=dist[u[i]]+dist[v[i]];
}else if(dist[u[i]]+dist[v[i]]==maxx) que[++len]=i;//相等要加到队列里
}
if(maxx<ans) ans=maxx;//更新答案
for(int i=1;i<=len;i++){
if(sub[u[que[i]]]!=sub[v[que[i]]]){//在不在路径上
printf("%d
",ans);
exit(0);
}
if(!las) las=sub[u[que[i]]];//如果不在路径上,那就在子树里,记录下
if(sub[u[que[i]]]!=las){//在不在同一子树里
printf("%d
",ans);
exit(0);
}
}
rt=0,sum=siz[las],groot(las,0),solve(rt);//递归
}
int main(){
memset(h,-1,sizeof h);
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&u[i],&v[i]);
}
sum=maxp[0]=n;
groot(1,0);
solve(rt);
printf("%d
",ans);
return 0;
return 0;
}