题意
给定一棵树,每个点有点权(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;
}