S t4 求调 二分加贪心
  • 板块学术版
  • 楼主Xlw6friend
  • 当前回复0
  • 已保存回复0
  • 发布时间2023/10/28 10:06
  • 上次更新2023/11/2 11:07:52
查看原帖
S t4 求调 二分加贪心
741169
Xlw6friend楼主2023/10/28 10:06

S T4 求调 用了两个二分和贪心 思路还是很清晰的 贪心思路是预处理该总天数下,每个节点最晚需要开始种树是第几天(f[i]),用一个优先队列维护每一个节点代表的子树中,需要最早开始种树的那个节点的是第几天(tr[i]=min(f[i])),优先队列维护队头tr[i]最小)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int n, b[MAXN], c[MAXN], u, v, l, r, ans, mid, f[MAXN], g[MAXN], tr[MAXN];
long long a[MAXN];
//f[i]表示该day下第i个节点最晚需要开始种树是第f[i]天 
//g[i]表示第i个节点从第g[i]天开始每天只能长1米 
//tr[i]表示第i个节点所在子树最小的f[i]值 
vector<int> e[MAXN];
struct cmp
{
	bool operator()(int a, int b)
	{
		return tr[a] > tr[b];
	}	
};
priority_queue<int, vector<int>, cmp> q;
void dfs(int u)
{
	tr[u] = f[u];
	for (int i = 0; i < e[u].size(); i++)
	{
		int v = e[u][i];
		dfs(v);
		tr[u] = min(tr[u], tr[v]);
	}
	return;
}
bool check(int day)
{
	memset(f, 0x3f3f3f3f, sizeof(f));
	memset(tr, 0x3f3f3f3f, sizeof(tr));
	for (int i = 1; i <= n; i++)
	{
		int ll = 0, rr = day, anss = -1, midd;
		long long x, y, add;
		while (ll <= rr)//查找f[i]表示该day下第i个节点最晚需要开始种树是第f[i]天 
		{
			midd = (ll+rr) >> 1;
			if (g[i] <= midd)
			{
				add = day-midd+1;	
			}
			else if (g[i] > midd && g[i] <= day)
			{
				x = b[i]+midd*c[i];//首项 
				y = b[i]+(g[i]-1)*c[i];//末项 
				add = (x+y)*(g[i]-midd)/2 + (day-g[i]+1);//等差数列 
			}
			else
			{
				x = b[i]+midd*c[i];//首项 
				y = b[i]+day*c[i];//末项 
				add = (x+y)*(day-midd+1)/2;//等差数列 
			}
			
			if (add >= a[i])//add=第mid天到第dayy天树长高的高度 
			{
				ll = midd+1;
				anss = midd;
			}
			else
				rr =  midd-1;
		}
		if (anss == -1)
			return false;
		f[i] = anss;
	}
	dfs(1);
	while (!q.empty())
		q.pop();
	q.push(1);
	int dayy = 0;
	while (!q.empty())
	{
		++dayy;
		int now = q.top();
		q.pop();
		for (int i = 0; i < e[now].size(); i++)
		{
			int v = e[now][i];
			if (dayy > f[v])
				return false;
			q.push(v);
		}
	}
	return true;
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
    	scanf("%ld%d%d", &a[i], &b[i], &c[i]);
    	if (c[i] >= 0) 
    		g[i] = 0x3f3f3f3f;
		else//b[i]<=x*-c[i]
			g[i] = ceil(b[i] / (-c[i]));
	}
    for (int i = 1; i <= n-1; i++)
    {
    	scanf("%d%d", &u, &v);
    	e[u].push_back(v);
	}
	l = n, r = 1e9;//最少天数n,最多1e9
	while (l<=r)
	{
		mid = (l+r) << 1;
		if (check(mid))
		{
			r = mid-1;
			ans = mid;
		}
		else
			l = mid+1;
	}
	cout << ans;
    return 0;
}


2023/10/28 10:06
加载中...