[Noip2015]运输计划
一.前言
阿这……我已经尽量把常数些小了,题目光明正大地卡常,sort自身就很魔幻……题目链接
二.思路
快快乐乐二分做法。可以直接二分时间,是满足性质的。对于每一个猜想mid?反正进行check的时候找出所有的时间大于 mid 的计划,然后找出有哪些道路(长度设为 u)是同时被所有计划经过,并且删掉以后满足 (mid+u>=计划时间_{max}),就很暴力……
关于道路经过数……可以差分做一个自下往上的前缀和(一个点被经过的次数也是点连父亲的那条边被经过的次数),将计划起终点的前缀和 +1 ,在 lca 处减 2,做前缀和就可以得到经过次数(推荐手玩理解)
做前缀和的时候顺便判删边就好。
三.CODE
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<fstream>
#include<cmath>
#include<cstring>
using namespace std;
int read(){
char ch=getchar();
int res=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())res=res*10+(ch-'0');
return res*f;
}
const int MAXN=300005;
int n,m,ans=1;
int head[MAXN],ne[2*MAXN],to[2*MAXN],dis[2*MAXN],tot;
void add(int x,int y,int z){to[++tot]=y,dis[tot]=z,ne[tot]=head[x],head[x]=tot;}
int dep[MAXN],f[MAXN][20],fdis[MAXN][20];
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
f[x][0]=fa;
for(int i=1;i<20;++i)
f[x][i]=f[f[x][i-1]][i-1],fdis[x][i]=fdis[x][i-1]+fdis[f[x][i-1]][i-1];
for(int i=head[x];i;i=ne[i]){
if(to[i]==fa)continue;
fdis[to[i]][0]=dis[i];
dfs(to[i],x);
}
}
inline int LCA(int x,int y,int &u){
int cnt=0;
if(dep[x]<dep[y])swap(x,y);
for(int i=19;i>=0;--i)if(dep[f[x][i]]>=dep[y])cnt+=fdis[x][i],x=f[x][i];
if(x==y){
u=x;
return cnt;
}
for(int i=19;i>=0;--i)if(f[x][i]!=f[y][i])
cnt+=fdis[x][i]+fdis[y][i],x=f[x][i],y=f[y][i];
u=f[x][0];
return cnt+fdis[x][0]+fdis[y][0];
}
struct road{
int s,t,alf,lca;
}r[MAXN];
bool cmp(road x,road y){
return x.alf>y.alf;
}
int sum[MAXN],u,cnt;
bool fl;
void solve(int x,int fa){
for(int i=head[x];i;i=ne[i]){
if(to[i]==fa)continue;
solve(to[i],x);
sum[x]+=sum[to[i]];
sum[to[i]]=0;
}
if(sum[x]==cnt&&x!=1&&fdis[x][0]>=u)fl=1;
}
bool check(int x){
u=r[1].alf-x,cnt=0;
for(int i=1;i<=m;++i){
if(r[i].alf<=x)break;
cnt++,sum[r[i].s]++,sum[r[i].t]++,sum[r[i].lca]-=2;
}
fl=0;
solve(1,0);sum[1]=0;
return fl;
}
int main(){
n=read();m=read();
for(int i=1,x,y,z;i<n;++i){
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
}
dfs(1,0);
for(int i=1;i<=m;++i){
r[i].s=read();r[i].t=read();
r[i].alf=LCA(r[i].s,r[i].t,r[i].lca);
}
sort(r+1,r+m+1,cmp);
int L=0,R=r[1].alf;
while(L<=R){
int mid=(L+R)>>1;
if(check(mid)){
ans=mid,R=mid-1;
}
else L=mid+1;
}
printf("%d",ans);
return 0;
}