NOIP2015 提高组] 运输计划

码农题啊兄弟们。

随便考虑二分一下,然后发现要取一条满足性质的边。

被所有大于(mid)的路径都覆盖,取了之后能把他们都弄到小于(mid)

那就树上差分再处理一下。
写了(180h),老年人复建训练。

NOIP2015 提高组] 运输计划
// Problem: P2680 [NOIP2015 提高组] 运输计划
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2680
// Memory Limit: 292.97 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define N 300005

inline ll read(){
	char a = getchar();
	ll ans = 0;
	while(!((a <= '9') && (a >= '0')))
	a = getchar();
	while((a <= '9') && (a >= '0'))
	ans = (ans << 3) + (ans << 1) + (a - '0'),a = getchar();
	return ans;
}

struct P{
	ll to,v,next;
}e[N << 1];

ll cnt,head[N],s[N];

inline void add(int x,int y,int v){
	e[++cnt].to = y;
	e[cnt].v = v;
	e[cnt].next = head[x];
	head[x] = cnt;
}

ll n,m;

struct T{
	ll l,r,sl;
}ta[N];

bool operator < (T a,T b){
	return a.sl < b.sl;
}

ll dep[N],f[N][32];

inline void dfs(int u,int fa){
	f[u][0] = fa;
	dep[u] = dep[fa] + 1;
	for(int i = 1;i <= 30;++i)
	f[u][i] = f[f[u][i - 1]][i - 1];
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == fa)continue;
		s[v] = s[u] + e[i].v;
		dfs(v,u);
	}
}

inline ll lca(ll x,ll y){
	if(dep[x] < dep[y])
	std::swap(x,y);
	for(int i = 30;i >= 0;--i){
		if(dep[f[x][i]] >= dep[y])
		x = f[x][i];
		if(x == y)
		return x;
	}
	for(int i = 20;i >= 0;--i){
		if(f[x][i] != f[y][i]){
			x = f[x][i];
			y = f[y][i];
		}
	}
	return f[x][0];
}

ll tag[N],va[N];

ll need;
bool p;
ll x;

inline void del(int u,int fa){
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v != fa){
			del(v,u);
			va[u] += va[v];
		}
	}
	va[u] += tag[u];
	// std::cout<<u<<" "<<tag[u]<<" "<<va[u]<<std::endl;	
}

inline void dfs2(int u,int fa,int v){
	// std::cout<<u<<" "<<va[u]<<" "<<tag[u]<<" "<<fa<<" "<<v<<std::endl;
	if(va[u] == need && ta[m].sl - v <= x){
		p = 1;
		return ;
	}
	for(int i = head[u];i;i = e[i].next){
		int vi = e[i].to;
		if(vi == fa)
		continue;
		dfs2(vi,u,e[i].v);
	}
}

inline bool check(){
	// std::cout<<x<<":"<<std::endl;
	std::memset(tag,0,sizeof(tag));
	std::memset(va,0,sizeof(va));	
	need = 0;
	for(int i = m;i >= 1;--i){
		if(ta[i].sl > x){
			int Lca = lca(ta[i].l,ta[i].r);
			need ++ ;
			if(Lca == ta[i].l){
				tag[ta[i].l] -- ;
				tag[ta[i].r] ++ ;
			}else if(Lca == ta[i].r){
				tag[ta[i].r] -- ;
				tag[ta[i].l] ++;
			}else {
				// std::cout<<Lca<<" "<<ta[i].l<<" "<<ta[i].r<<std::endl;
				tag[Lca] -= 2;
				tag[ta[i].l] ++ ;
				tag[ta[i].r] ++ ;
			}
		}
	}
	del(1,0);
	p = 0;
	dfs2(1,0,0);
	return p;
}

inline void find_ans(){a
	std::sort(ta + 1,ta + m + 1);
	ll l = 0,r = ta[m].sl;
	#define mid ((l + r) >> 1)
	while(l + 1 < r){
		x = mid;
		// std::cout<<l<<" "<<r<<" ";
		if(check())
			r = mid;
		else 
			l = mid;
		// std::cout<<l<<" "<<r<<std::endl;
	}ac
	r ++ ;
	while(x = r - 1,check())
	r--;
	std::cout<<r<<std::endl;
}

int main(){
	n = read(),m = read();
	for(int i = 1;i <= n - 1;++i){
		ll l,r,v;
		l = read(),r = read(),v = read();
		add(l,r,v);
		add(r,l,v);
	}
	for(int i = 1;i <= m;++i)
	ta[i].l = read(),ta[i].r = read();
	dfs(1,0);
	for(int i = 1;i <= m;++i){
		ll Lca = lca(ta[i].l,ta[i].r);
		ta[i].sl = s[ta[i].l] + s[ta[i].r] - 2 * s[Lca];
	}
	// for(int i = 1;i <= m;++i)
	// std::cout<<ta[i].sl<<std::endl;
	find_ans();
}

原文地址:https://www.cnblogs.com/dixiao/p/14987742.html