「NOIP2015」运输计划 (树上差分,二分答案)
题目简介
咕咕咕。
分析
需要对其进行二分答案。
对于二分获得的答案 \(mid\) ,如果存在一边 \(e\) 使最长航线 \(\mbox{max}_{dis}\) 满足 \(\mbox{max}_{dis}-dis(e)<=mid\) 且所有比 \(mid\) 长的航线都经过 \(e\) ,则 \(mid\) 是满足的;
若 \(mid\) 满足,则在 \([l,mid-1]\) 区间继续二分寻找更小的答案,否则在 \([mid+1,r]\) 区间寻找更大的答案。
中途使用 \(LCA\) 和树上差分处理航线的长度以及对航线的统计。
可以先排序,更方便查找。
AC Code
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int read(){
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x;
}
const int Maxn=3e5+5;
const int Inf=0x3f3f3f3f;
struct Adjacency_List{
int nxt;
int t,dis;
}tr[Maxn<<1];
int h[Maxn];
int tot;
void add(int x,int y,int z){
tr[++tot].nxt=h[x];
tr[tot].t=y;
tr[tot].dis=z;
h[x]=tot;
}
int n,m;
int t;
int w[Maxn];
int dep[Maxn];
int f[Maxn][22];
void prep(int x,int fa){
dep[x]=dep[fa]+1;
f[x][0]=fa;
// cout<<"dep["<<x<<"] = "<<dep[x]<<'\n';
for(int i=1;i<=t;i++)
f[x][i]=f[f[x][i-1]][i-1];
for(int i=h[x];i;i=tr[i].nxt){
int y=tr[i].t;
if(y==fa)continue;
w[y]=w[x]+tr[i].dis;
prep(y,x);
}
}
int lca(int x,int y){
// cout<<" "<<dep[x]<<' '<<dep[y]<<endl;
if(dep[x]<dep[y])swap(x,y);
for(int i=t;i>=0;i--){
if(dep[f[x][i]]>=dep[y])
x=f[x][i];
if(x==y)return x;
}
// cout<<x<<" "<<y<<endl;
for(int i=t;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
struct course{
int st,ed;
int lca;
int lengh;
course(){}
course(const int x){lengh=x;}
friend bool
operator <(course fir,course sec){
return fir.lengh<sec.lengh;
}
}a[Maxn];
inline int &mymax(int &fir,int &sec){return fir>sec?fir:sec;}
int d[Maxn];
bool dfs(int x,int fa,int cnt,int k){
for(int i=h[x];i;i=tr[i].nxt){
int y=tr[i].t;
if(y==fa)continue;
if(dfs(y,x,cnt,k))return 1;
d[x]+=d[y];
}
// if(d[x]==cnt&&a[n].lengh-w[x]+w[f[x][0]]<=k)
// printf(" k = %d\n",x);
return d[x]==cnt&&a[m].lengh-w[x]+w[f[x][0]]<=k;
}
bool check(int x){
memset(d,0,sizeof d);
int b=upper_bound(a+1,a+1+m,course(x))-a;
// printf(" start %d\n",b);
int cnt=0;
for(int i=b;i<=m;i++){
d[a[i].st]++;
d[a[i].ed]++;
d[f[a[i].lca][0]]-=2;
cnt++;
}
return dfs(1,0,cnt,x);
}
int main(){
// freopen("data.in","r",stdin);
n=read(),m=read();
t=log(n)/log(2)+1;
for(int i=1;i^n;i++){
int x=read(),y=read(),z=read();
add(x,y,z);
add(y,x,z);
}
prep(1,0);
// printf(" w[] : ");
// for(int i=1;i<=n;i++)
// printf("%d ",w[i]);
// puts("");
// for(int i=1;i<=n;i++)
// cout<<f[i][0]<<' ';
// cout<<'\n';
for(int i=1;i<=m;i++){
a[i].st=read();
a[i].ed=read();
a[i].lca=lca(a[i].st,a[i].ed);
// cout<<a[i].lca<<'\n';
a[i].lengh=
w[a[i].st]+w[a[i].ed]-(w[a[i].lca]<<1);
// printf(" a[%d].lengh = %d\n",i,a[i].lengh);
}
sort(a+1,a+1+m);
// puts(" After sort()");
// for(int i=1;i<=m;i++)
// printf(" a[%d].lengh = %d\n",i,a[i].lengh);
int l=0,r=a[m].lengh;
int ans;
while(l<=r){
int mid=(l+r)>>1;
// printf(" MID = %d\n",mid);
if(check(mid)){
ans=mid;
r=mid-1;
}else
l=mid+1;
}
printf("%d\n",ans);
return 0;
}