CSP-S T4

发布时间 2023-11-07 07:35:00作者: 颈流推进

考虑二分,对于每一个节点处理出一个最慢的选择时间,对其排序,跟着选就行了

反正我考场上是没有想出来这个东西,所以这里来详细的证明一下

对于一对点 \(x,y\),不难发现有一些性质

  • 无论先选哪一个,总用时都是相同的,选完之后树的形态是相同的
  • 想要选这两个点中的一个,都必须先选 \(lca(x,y)\) 到根的路径,所以选择的顺序对后选的那一个的花费时间是没有影响的
  • 考虑设 \(x\) 的截止时间小于 \(y\),假设一定有解,若先选 \(x\) 超时,那一定是 \(y\) 超时了,否则与假设不符,如果 \(y\) 超时,那不难发现一定无解,因为反过来给 \(x\) 分配更长的时间更容易趋势

所以考虑排序,然后做就行了

复杂度 \(O(n\log{n}\log{V})\)

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define fp(a,b,c) for(int a=(int)b;i<=(int)c;++a)
#define fd(a,b,c) for(int a=(int)b;i>=(int)c;--a)
#define inf 0x3f3f3f3f
#define pii pair<int,int>
#define fir first
#define sec second 
#define mpr make_pair
#define ll long long 
#define i128 __int128_t
#define met(x,y) memset(x,y,sizeof(x))
#define int ll

using namespace std;

inline int rd(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)) f=(ch^'-')?1:-1,ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x*f;}
const int N=1e5+10;
int n;
int a[N],b[N],c[N],fa[N],tp[N],pp[N],tim[N];
int last[N],ord[N],vis[N];
vector<int> g[N];

void dfs(int now,int f){
	fa[now]=f;for(int x:g[now]) if(x^f) dfs(x,now);
}

i128 C2(ll l,ll r){
	if(r<l) return 0;
	return (i128)(r+l)*(r-l+1)/2;
}

i128 ccalc(int l,int r,int id){
	i128 pu=(i128)(C2(l,r)*c[id]+b[id]*(r-l+1));
	return pu;
}

ll calc(int st,int ed,int id){
	i128 r=0;
	if(pp[id]>=st&&pp[id]<=ed){
		if(tp[id]==1){
			r+=ed-pp[id]+1;
			if(st<pp[id]) r+=ccalc(st,pp[id]-1,id);
		}else {
			r+=pp[id]-st+1;
			if(ed>pp[id]) r+=ccalc(pp[id]+1,ed,id);
		}
	}
	else if(pp[id]<=ed&&tp[id]==1){
		r=ed-st+1;
	}
	else r=ccalc(st,ed,id);
	return (ll)min((i128)1e18,r);
}

int bs(int lim,int id){
	int l=1,r=lim,ans=-1;
	while(l<=r){
		int mid(l+r>>1);
		if(calc(mid,lim,id)>=a[id])
			ans=mid,l=mid+1;
		else r=mid-1;
	}
	return ans;
}

bool check(int lim){
	fp(i,1,n){
		tim[i]=bs(lim,i);
		if(tim[i]==-1) return false;
	}
	iota(ord+1,ord+n+1,1);
	sort(ord+1,ord+n+1,[&](int x,int y){return tim[x]<tim[y];});
	int T=0;
	met(vis,0);
	fp(i,1,n){
		int now=ord[i];
		while(now&&!vis[now])++T,vis[now]=1,now=fa[now];
		if(T>tim[ord[i]]) return false;
	}
	return true;
}

int cel(int x,int y){
	if(x%y==0) return x/y;
	return x/y+1;
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	n=rd();
	fp(i,1,n)
		a[i]=rd(),b[i]=rd(),c[i]=rd();
	fp(i,1,n){
		if(c[i]<0)
			tp[i]=1,pp[i]=cel(-b[i],c[i]);
		if(b[i]<=0){
			if(!c[i]) tp[i]=2,pp[i]=0;
			else tp[i]=2,pp[i]=-b[i]/c[i];
		}
	}
	fp(i,1,n-1){
		int u=rd(),v=rd();
		g[u].emplace_back(v),
		g[v].emplace_back(u);
	}	
	dfs(1,0);
	int l=n,r=1e9,ans=n;
	while(l<=r){
		int mid(l+r>>1);
		if(check(mid)) ans=mid,r=mid-1;
		else l=mid+1;
	}
	cout << ans << endl;
	return 0;
}