【NOIP2015提高组Day2T3】运输计划

前置思路

这个题目这里提供的解题思路就是 二分+LCA+树上边差分。

思路

大体上就是原来的边上差分模板,这里不在过多赘述。

while(m--){
	cin>>f1>>f2;
	f3=1;
	c[f1]+=f3;
	c[f2]+=f3;
	c[lca(f1,f2)]-=f3*2;
}

主要就是判断这个答案是什么?

我们这里定义 d 表示最大完成时间,这里同边差分一样,我们直接计算得到 \(d=c_u+c_v-c_{lca(u,v)}\)

然后我们就暴力去尝试,枚举每个航线,看这个时间是否在阈值之外,这样我们就考虑修改这个航线上面的地方,然后找到所有超过阈值的所有航线的交点,一定修改这里因为修改这里会让结果最小化。

可是,恭喜你——超时了!

超时了怎么办? 题目给了很明显的题目“最长的最小”显然二分答案。

标程代码

恭喜你——AC了!

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
int read(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch == '-') f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void write(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}
const int N=300005;
struct node{
	int u,v,lca,d;
}a[N];
int n,m,f1,f2,f3,maxn,l,r,mid,ecnt,ect;
int dep[N],fa[N][20],c[N],d[N],dfn[N],b[N],h[N];
struct edge{
	int v,p,w;
}e[N<<1];
void add(int u,int v,int w){
	ect++;
	e[ect]=edge{v,h[u],w};
	h[u]=ect;
	return ;
}
void dfs(int u,int f){
	fa[u][0]=f;
	ecnt++;
	dfn[u]=ecnt;
	for(int i=1;i<=19;++i) fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=h[u];i;i=e[i].p){
		int v=e[i].v;
		if(v==f) continue;
		int w=e[i].w;
		dep[v]=dep[u]+1;
		c[v]=c[u]+w;
		b[v]=w;
		dfs(v,u);
	}
	return ;
} 
int lca(int u,int v){
	if(dep[u]<dep[v]) swap(u,v);
	int d=dep[u]-dep[v],k=0;
	while(d!=0){
		if(d&1) u=fa[u][k];
		d>>=1;
		k++;
	}
	if(u==v) return u;
	for(int i=19;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[u][0];
}
void tree_cha(int u,int fa){
	for(int i=h[u];i;i=e[i].p){
		int v=e[i].v;
		if(v==fa) continue;
		tree_cha(v,u);
		d[u]+=d[v];
	}
	return ;
}
bool cheak(int kx){
	int tot=0;
	for(int i=1;i<=m;++i){
		if(a[i].d>kx){
			tot++;
			d[a[i].u]++;
			d[a[i].v]++;
			d[a[i].lca]-=2;
		}
	}
	tree_cha(1,1);
	bool can=0;
	for(int i=1;i<=n;++i){
		if(d[i]==tot&&maxn<=kx+b[i]) can=1;
		d[i]=0;
	}
	return can;
}
int main(){
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
//	cin>>n>>m;
	n=read();
	m=read();
	for(int i=1;i<n;++i){
//		cin>>f1>>f2>>f3;
		f1=read();
		f2=read();
		f3=read();
		add(f1,f2,f3);
		add(f2,f1,f3);
	}
	dfs(1,1);
	for(int i=1;i<=m;++i){
//		cin>>a[i].u>>a[i].v;
		a[i].u=read();
		a[i].v=read();
		a[i].lca=lca(a[i].u,a[i].v);
		a[i].d=c[a[i].u]+c[a[i].v]-2*c[a[i].lca];
		maxn=max(maxn,a[i].d);
	}
	l=0;
	r=maxn;
	while(l<=r){
		mid=(l+r)>>1;
		if(cheak(mid)) r=mid-1;
		else l=mid+1;
	}
//	cout<<l;
	write(l);
	return 0;
}
posted on 2026-01-11 22:50  不爱吃KC的KC  阅读(2)  评论(0)    收藏  举报