[Noip2015]运输计划

[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;
} 
原文地址:https://www.cnblogs.com/clockwhite/p/13505526.html