• IOI2021集训队作业 207PE


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

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

    问是否能够到达(T)

    (nle 10^5)


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

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

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

    1. (b_ige 0>b_j)
    2. (b_i,b_jge 0and a_i<a_j)
    3. (b_i,b_j<0and 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
    ");
    		else
    			printf("escaped
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    DB2 v8.2,v9.1,v9.5,v9.7下载地址及详细安装图解
    Windows Server 2008 R2遗忘管理员密码后的解决方案
    weblogic的域模式(生产模式、开发模式)
    Linux shell编程 字符串拼接
    Linux rsync命令详解
    oracle 日志组管理
    T-SQL编程规范
    数据库编程起别名的3中方式
    windows server下安装SSHD服务
    网线中的5类线、超5类线、6类线有什么区别?
  • 原文地址:https://www.cnblogs.com/jz-597/p/13865681.html
Copyright © 2020-2023  润新知