「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;
}

$$-----EOF-----$$

posted @ 2022-01-24 21:31  AlienCollapsar  阅读(35)  评论(0编辑  收藏  举报
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq