HDU 6326

题意:
一棵结点数为n的树,除1号结点外都有一个怪兽,消灭第i个结点上的怪兽会消耗ai的HP,但消灭完之后会恢复bi的HP。现在从结点1出发去打怪,最少初始时含有多少HP才能保证能打完所有的怪,而且任何时候的HP都不为负。

题解:
以1为根,将无根树变为有根树。要想消灭结点x的怪兽,必须先消灭x的父亲结点上的怪兽。

当不考虑消灭要先消灭的父亲的限制时,就是说可以随便、任意选择顺序的情况。

考虑两个结点i和j的消灭顺序:

若两者都是啊a<b的情况,说明消灭后会提升HP,所以应该优先消灭(相对于会降低HP的结点),但不同的顺序对于初始的HP的要求不同,所以应该优先消灭需要“本钱”少的,就是要以a的升序来消灭怪兽。

若两者都是a>b的情况,考虑最后最后一定是可以消灭完所有的怪兽的(因为初始可以有足够的HP),那么消灭完最后一个怪兽后,所剩的HP一定最后一个怪兽的b,这是显然的,不然会有“浪费”。由于初始HP和最后HP的差值与顺序无关(都是\sum_{i=1}^{n}b_i-\sum_{i=1}^{n}a_i),所以要使初始HP最小,最后所剩的HP也应该最小。就是要以b的降序来消灭怪兽。

若两者一个满足a<b,一个满足a>b,肯是要先消灭能提升HP的那一个。

根据以上关系就可以确定怪兽消灭的优先级。

现在考虑加上消灭x,必须先消灭father[x]的限制:

考虑先在优先级最高的结点:x,必须先消灭father[x],而且是消灭完father[x]后,就应该立刻取消灭x,因为x在那里已经等着被消灭的望穿秋水了。于是我们就可以将father[x]和x两个结点当作一个结点考虑,将两个结点“合并”成一个结点,然后合并n-2次就合并成一个结点了,这时的a就是答案。

合并方法:

father[x]的b值大于x的b值,那么father[x]新的b值为b-bx

father[x]的b值小于x的b值,那么father[x]新的a值为a+(ax-b),b值为bx。

代码:

#include<bits/stdc++.h>
#define N 100010
#define INF 1e9
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define eps 1e-8
#define P 1000000007
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
struct node
{
	LL x,y,id;
	bool operator <(const node z) const
	{
	    if (x<y && z.x<z.y) return x>z.x;
		if (y<=x && z.y<=z.x) return y<z.y;
		if (y<=x && z.y>z.x) return true;
		return false;
	}
}a[N];
priority_queue<node>q;
int fa[N];
bool v[N];
vector<int>G[N];

void dfs(int x,int p)
{
	for(auto i:G[x])if (i!=p) fa[i]=x,dfs(i,x);
}

int getfa(int x)
{
	if (!v[fa[x]]) return fa[x];
	return fa[x]=getfa(fa[x]);
}

int main()
{
	IO
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		for (int i=2;i<=n;i++)
		{
			cin>>a[i].x>>a[i].y;a[i].id=i;
			q.push(a[i]); v[i]=0; G[i].cl();
		}
		G[1].cl(); a[1].x=a[1].y=a[1].id=0; fa[1]=1; v[1]=0;
		for (int i=1;i<n;i++)
		{
			int j,k;
			cin>>j>>k;
			G[j].pb(k);G[k].pb(j);
		}
		dfs(1,0);
		while(!q.empty())
		{
			node c=q.top();q.pop();
			if (!(c.x==a[c.id].x && c.y==a[c.id].y) || v[c.id]) continue;
			int ff=getfa(c.id); node t=a[ff];
			a[ff].x+=max(a[ff].y,a[c.id].x)-a[ff].y;
			if (a[ff].y>a[c.id].x)a[ff].y-=(a[c.id].x-a[c.id].y);else a[ff].y=a[c.id].y;
			if (ff!=1 && !(a[ff].x==t.x && a[ff].y==t.y)) q.push(a[ff]);
			v[c.id]=1;
		}
		cout<<a[1].x<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/nudt_spy/article/details/81319300
hdu
今日推荐