IOI2021集训队作业 207PE

一棵树,每个点有个权值\(v_i\)

从根节点开始,每次遍历与走过的点联通的未走过的点,使得\(v_i\)的前缀和的最小值大于等于\(0\)

问是否能够到达\(T\)

\(n\le 10^5\)


经典贪心。。。然而由于不知道怎么处理终点而搞了几天。。。

可以将一个点看成\((a_i,b_i)\)的形式,表示前缀和的最小值为\(-a_i\),遍历了这个点可以得到\(b_i\)的收益。

如此定义\((a_i,b_i)\)\((a_j,b_j)\)优:

  1. \(b_i\ge 0>b_j\)
  2. \(b_i,b_j\ge 0\and a_i<a_j\)
  3. \(b_i,b_j<0\and a_i+b_i>a_j+b_j\)

先求出每个点的初始状态,每次找到最优的,和它的父亲合并。

这样适用于遍历整棵树的情况。如果只要求到达\(T\),把\(b_T\)设为无限大即可。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200005
#define ll long long
#define INF 1000000000000000
int n,T;
struct EDGE{
	int to;
	EDGE *las;
} e[N*2];
int ne;
EDGE *last[N];
void link(int u,int v){
	e[ne]={v,last[u]};
	last[u]=e+ne++;
}
int fa[N];
void init(int x){
	for (EDGE *ei=last[x];ei;ei=ei->las)
		if (ei->to!=fa[x])
			fa[ei->to]=x,init(ei->to);
}
int dsu[N];
int getdsu(int x){return dsu[x]==x?x:dsu[x]=getdsu(dsu[x]);}
struct Status{ll a,b;int id;} s[N];
bool cmp(Status son,Status fa){
	if (fa.b>=0 && son.b>=0)
		return fa.a<son.a;
	if (fa.b<0 && son.b<0)
		return fa.a+fa.b>son.a+son.b;
	return fa.b>son.b;
}
Status q[N*2];
int nq;
void merge(int y,int x){
	dsu[x]=y;
	s[y].a=max(s[y].a,-s[y].b+s[x].a);
	s[y].b=s[y].b+s[x].b;
}
int main(){
	int Q;
	scanf("%d",&Q);
	while (Q--){
		scanf("%d%d",&n,&T);
		ne=0;
		memset(last,0,sizeof(EDGE*)*(n+1));
		for (int i=1;i<=n;++i){
			int x;
			scanf("%d",&x);
			if (x<0)
				s[i]={-x,x,i};
			else
				s[i]={0,x,i};
		}
		s[T].b=INF;
		for (int i=1;i<n;++i){
			int u,v;
			scanf("%d%d",&u,&v);
			link(u,v);
			link(v,u);
		}
		init(1);
		for (int i=1;i<=n;++i)
			dsu[i]=i;
		nq=0;
		for (int i=2;i<=n;++i)
			q[nq++]=s[i];
		make_heap(q,q+nq,cmp);
		while (nq){
			Status x=q[0];
			pop_heap(q,q+nq--,cmp);
			if (s[x.id].a!=x.a || s[x.id].b!=x.b || getdsu(x.id)!=x.id)
				continue;
			int y=getdsu(fa[x.id]);
			merge(y,x.id);
			if (y!=1){
				q[nq++]=s[y];			
				push_heap(q,q+nq,cmp);
			}
			else if (getdsu(T)==1)
				break;
		}
		if (s[1].a>0)
			printf("trapped\n");
		else
			printf("escaped\n");
	}
	return 0;
}
posted @ 2020-10-23 18:56  jz_597  阅读(109)  评论(0编辑  收藏  举报