传送门:
洛谷:https://daniu.luogu.org/problemnew/show/2680#sub
(链接给的是大牛分站的,主站上T了一个点,大牛分站A了,“高性能”,卡常数)
UOJ:http://uoj.ac/problem/150
题目分析
给出一棵
解题分析
最大中求最小,套路想到二分。二分答案ans,预先LCA求出每个任务所需时间,判断出有多少个运输计划超出了ans。
因为题目中要求只能选一条边,所以我们肯定要求这条边在所有超出ans的运输计划,而且这条边肯定尽可能地大。可以用差分来找出有没有这条边。先刷出所有超出ans的运输计划个数k和最大的差距tem,然后sum数组,对于每一个计划
注意每个任务的LCA值建议存储起来节省空间。
复杂度:
时间:
空间:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 300005
#define maxe 600005
using namespace std;
int n,m,tot,len,ans,s[maxn],t[maxn],dis[maxn],cst[maxn],son[maxe],nxt[maxe],w[maxe],lnk[maxn],dep[maxn],fa[maxn][20],sum[maxn],v[maxn],la[maxn];
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void readi(int &x){
x=0; char ch=nc();
while ('0'>ch||ch>'9') ch=nc();
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=nc();}
}
void _add(int x,int y,int z){
son[++tot]=y; w[tot]=z; nxt[tot]=lnk[x]; lnk[x]=tot;
}
void _dfs(int x,int dad){
for (int j=lnk[x];j;j=nxt[j])
if (son[j]!=dad){
dep[son[j]]=dep[x]+1; dis[son[j]]=dis[x]+w[j]; _dfs(son[j],x); fa[son[j]][0]=x; v[son[j]]=w[j];
}
}
void _init(){
freopen("transport.in","r",stdin);
freopen("transport.out","w",stdout);
readi(n); readi(m); dis[1]=dep[0]=0;
for (int i=1,x,y,z;i<n;i++){
readi(x); readi(y); readi(z);
_add(x,y,z); _add(y,x,z);
}
dep[1]=1;_dfs(1,0); len=19;
for (int j=1;j<=len;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int _LCA(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int j=len;j>=0&&dep[x]>dep[y];j--) if (dep[fa[x][j]]>=dep[y]) x=fa[x][j];
if (x==y) return x;
for (int j=len;j>=0;j--)
if (fa[x][j]!=fa[y][j]) {x=fa[x][j]; y=fa[y][j];}
return fa[x][0];
}
void dfsc(int x,int dad){
for (int j=lnk[x];j;j=nxt[j])
if (son[j]!=dad) {dfsc(son[j],x); sum[x]+=sum[son[j]];}
}
bool _check(int x){
int tem=0,k=0; memset(sum,0,sizeof(sum));
for (int i=1;i<=m;i++)
if (cst[i]>x){
sum[s[i]]++; sum[t[i]]++; sum[la[i]]-=2;
k++; tem=max(tem,cst[i]-x);
}
if (tem==0) return 1;
dfsc(1,0); for (int i=2;i<=n;i++) if (sum[i]==k&&v[i]>=tem) return 1;
return 0;
}
void _solve(){
int L=0,R=0,mid;
for (int i=1;i<=m;i++){
readi(s[i]); readi(t[i]); la[i]=_LCA(s[i],t[i]);
cst[i]=dis[s[i]]+dis[t[i]]-(dis[la[i]]<<1); R=max(R,cst[i]);
}
while (L<=R){
mid=(R-L)/2+L;
if (_check(mid)) R=mid-1; else L=mid+1;
}
printf("%d",L);
}
int main()
{
_init();
_solve();
return 0;
}