gym100299E
题意
给定一棵树,每个点有点权\(a_i\),从根出发,到达给定的一个节点\(t\),初始有血量(hp)为\(0\),第一次经过点\(i\),有\(\text{hp}+a_i\),任意时刻必须满足\(\text{hp}\ge 0\),输出是否能到达\(t\)。
做法
考虑顺序遍历一条链,他们的值分别为:\(a_1,a_2,\cdots,a_{k-1},a_k\)
令\(b_i=\sum\limits_{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_2\cdots -l_m+r_m\)。
这样的实际意义在于\(\sum\limits_{k=1}^{i-1}(l_k+r_k) +l_{i},\sum\limits_{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 l\le r'\):\([l',r']+[l,r]=[l',r'+(-l+r)]\)。
那么将两个长度为\(m_1,m_2\)的序列可以在\(O((m_1+m_2)\text{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;
}