zoukankan      html  css  js  c++  java
  • gym100299E

    题意

    给定一棵树,每个点有点权(a_i),从根出发,到达给定的一个节点(t),初始有血量(hp)为(0)第一次经过点(i),有( ext{hp}+a_i),任意时刻必须满足( ext{hp}ge 0),输出是否能到达(t)

    做法

    考虑顺序遍历一条链,他们的值分别为:(a_1,a_2,cdots,a_{k-1},a_k)
    (b_i=sumlimits_{k=1}^i a_i)

    我们考虑序列({b_i})的关键值,描述成([l_1,r_1][l_2,r_2]cdots[l_m,r_m])(满足(l_i<r_i)(r_{i-1}<l_i)

    表示沿着这条链走,会经历(-l_1+r_1-l_2+r_2cdots -l_m+r_m)
    这样的实际意义在于(sumlimits_{k=1}^{i-1}(l_k+r_k) +l_{i},sumlimits_{k=1}^i (l_k+r_k))是严格的前缀最小值和前缀最大值,(r_i)(l_i)后的第一个前缀最大值的位置,(l_i)(r_{i-1})后的第一个前缀最小值的位置。
    当然可能会扔掉序列({b})的某个后缀,这对应于后面这个后缀对答案起不到有效的贡献。

    现在考虑两条链的策略
    引理:对于两条链({[a_1,a_2],[a_3,a_4],cdots})({[b_1,b_2],[b_3,b_4],cdots}),第一步走(a_1,b_1)较小者是一个不劣的策略。

    我们知道了两条链的策略,那么是可以进行合并操作的。
    一般的,向二元组序列(S={[l_1,r_1][l_2,r_2]cdots[l_m,r_m]})插入([l',r'])

    (S)是一堆不交的区间,将([l',r'])插入其中,我们查看与其相交的区间,假设为([l,r]),顺序合并,根据引理我们已经确定了偏序关系。
    那么合并为(l'le lle r')([l',r']+[l,r]=[l',r'+(-l+r)])

    那么将两个长度为(m_1,m_2)的序列可以在(O((m_1+m_2) ext{log}(m_1+m_2)))复杂度内合并。

    类似的,将([l',r'])强制向二元组序列(S={[l_1,r_1][l_2,r_2]cdots[l_m,r_m]})首部插入也同理。(子树的根)。

    利用启发式合并,总复杂度是(O(nlog^2n))的。

    code

    #include<bits/stdc++.h>
    typedef int LL;
    typedef double dl;
    #define opt operator
    #define pb push_back
    #define pii std::pair<LL,LL>
    const LL maxn=2e5+9,mod=998244353,inf=0x3f3f3f3f;
    LL Read(){
    	LL x(0),f(1); char c=getchar();
    	while(c<'0' || c>'9'){
    		if(c=='-') f=-1; c=getchar();
    	}
    	while(c>='0' && c<='9'){
    		x=(x<<3ll)+(x<<1ll)+c-'0'; c=getchar();
    	}return x*f;
    }
    void Chkmin(LL &x,LL y){
    	if(y<x) x=y;
    }
    void Chkmax(LL &x,LL y){
    	if(y>x) x=y;
    }
    LL add(LL x,LL y){
    	return x+=y,x>=mod?x-mod:x;
    }
    LL dec(LL x,LL y){
    	return x-=y,x<0?x+mod:x;
    }
    LL mul(LL x,LL y){
    	return 1ll*x*y%mod;
    }
    LL Pow(LL base,LL b){
    	LL ret(1); while(b){
    		if(b&1) ret=mul(ret,base); base=mul(base,base); b>>=1;
    	}return ret;
    }
    LL n,t;
    LL a[maxn];
    std::map<LL,LL> S[maxn];
    std::vector<LL> V[maxn];
    #define ite std::map<LL,LL>::iterator
    void Insert(std::map<LL,LL> &A,pii x){
    	ite it1,it2,it3;
    	it1=A.find(x.first);
    	if(it1==A.end()){
    		A.insert(x); it1=A.find(x.first);
    	}else{
    		it1->second+=x.second;
    	}
        if((it2=it1)!=A.begin()){
    		--it2;
    		if(it1->first<=it2->second){
    			it2->second+=-it1->first+it1->second;
    			A.erase(it1); it1=it2;
    		}
    	}
    	for(it2=it1,++it2;it2!=A.end();){
    		if(it2->first<=it1->second){
    			it1->second+=-it2->first+it2->second;
    			it3=it2; ++it3;
    			A.erase(it2);
    			it2=it3;
    		}else break;
    	}
    }
    void Merge(std::map<LL,LL> &A,std::map<LL,LL> &B){
    	if(A.size()>B.size()) A.swap(B);
    	for(ite it1=B.begin();it1!=B.end();++it1){
    		Insert(A,pii(it1->first,it1->second));
    	}
    }
    void Modify(std::map<LL,LL> &A,LL x){
    	ite it1;
    	for(it1=A.begin();it1!=A.end();++it1){
    		x+=it1->first;
    		if(x<it1->second){
    			LL y(it1->second);
    			A.erase(A.begin(),++it1);
    			A.insert(pii(x,y));
    			return;
    		}else{
    			x-=it1->second;
    		}
    	}
    	A.clear();
    }
    void Dfs(LL u,LL f){
    	if(u==t){
    		if(a[u]>=0) S[u].insert(pii(0,inf));
    		else S[u].insert(pii(-a[u],inf));
    		return;
    	}
    	for(LL i=0;i<V[u].size();++i){
    		LL v(V[u][i]); if(v==f) continue;
    		Dfs(v,u);
    		Merge(S[u],S[v]);
    	}
    	if(a[u]>=0){
    		Insert(S[u],pii(0,a[u]));
    	}else{
    		Modify(S[u],-a[u]);
    	}
    }
    void Clear(){
    	for(LL i=1;i<=n;++i){
    		std::vector<LL>().swap(V[i]);
    		S[i].clear();
    	}
    }
    void Solve(){
    	n=Read(); t=Read();
    	for(LL i=1;i<=n;++i) a[i]=Read();
    	for(LL i=1;i<n;++i){
    		LL x(Read()),y(Read());
    		V[x].pb(y); V[y].pb(x);
    	}
    	Dfs(1,0);
    	LL s(0);
    	ite it1;
    	LL flag(1);
    	for(it1=S[1].begin();it1!=S[1].end();++it1){
    		s-=it1->first;
    		flag&=(s>=0);
    		s+=it1->second;
    	}
    	if(flag) puts("escaped");
    	else puts("trapped");
    	Clear();
    }
    int main(){
    	LL T=Read();
    	while(T--){
    		Solve();
    	}
    	return 0;
    }
    
  • 相关阅读:
    如何用js得到当前页面的url信息方法(JS获取当前网址信息)
    可拖动大小div案例
    div内div水平垂直居中
    div设置absolute情况下填充剩余宽度
    最近很不顺
    [转载]什么是对象序列化,为什么要使用
    mac下安装eclipse以及python
    Myeclipse 10 for mac 破解版下载安装及破解方法
    IOS7学习之路一(新UI之自定义UITableViewCell)
    Xcode5和ObjC新特性
  • 原文地址:https://www.cnblogs.com/Grice/p/14517294.html
Copyright © 2011-2022 走看看