P7011-[CERC2013]Escape【堆,启发式合并】
正題
題目鏈接:https://www.luogu.com.cn/problem/P7011
題目大意
給出nnn個點的一棵樹,從一出發,要走到 ttt。初始時權值為000,每個節點有一個權值wiw_iwi?,第一次走過這個節點時會讓權值加上該節點的權值,要求全程權值不能為負數,求能否走到ttt。
1≤n≤2×1051\leq n\leq 2\times 10^51≤n≤2×105
解題思路
第一個比較麻煩的點是有一個終點的限制,我們走到終點之后就不需要考慮其他點了,不妨在終點后接一個權值為+∞+\infty+∞的節點,然后問題變為能否遍歷全樹。
接下來我們會發現有個很麻煩的點,因為對于一個子樹我們可能進入多次,一個比較暴力的想法是我們可以設fx,jf_{x,j}fx,j?表示我們在權值為jjj的時候進入xxx的子樹再出來時能夠變為的最大權值。
假設我們權值從jjj增加到了j+kj+kj+k,那么再進入能夠獲得的貢獻就是fi,j+k?fi,jf_{i,j+k}-f_{i,j}fi,j+k??fi,j?,不難發現對于一個fi,jf_{i,j}fi,j?不同的權值個數只有最多子樹大小個。考慮維護這些變換的位置,記為若干個二元組(x,y)(x,y)(x,y)表示權值為xxx時進入能夠獲得yyy的權值,顯然的我們有這些區間[x,x+y][x,x+y][x,x+y]是不相交的(因為如果相交那么可以一次獲得更多權值)。
而合并的時候我們直接暴力把這些區間合并(因為即使表現上相交了,我們可以后續考慮節點權值的時候再合并這些區間),然后根據節點xxx的權值暴力合并前面的區間。
至于兩個堆的合并自然可以用可并堆但是不如啟發式合并好寫。
時間復雜度:O(nlog?2n)O(n\log^2 n)O(nlog2n)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long #define mp(x,y) make_pair(x,y) using namespace std; const ll N=2e5+10; struct node{ll to,next; }a[N<<1]; ll T,n,t,tot,ls[N],p[N],w[N]; priority_queue<pair<ll,ll> >q[N]; void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return; } void dfs(ll x,ll fa){p[x]=x;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;dfs(y,x);if(q[p[y]].size()>q[p[x]].size())swap(p[x],p[y]);while(!q[p[y]].empty()){q[p[x]].push(q[p[y]].top());q[p[y]].pop();}}pair<ll,ll> k=mp(0,w[x]);while(!q[p[x]].empty()){pair<ll,ll> z=q[p[x]].top();z.first=-z.first;if(k.second>=0&&z.first>k.first+k.second)break;k=mp(max(k.first,z.first-k.second),k.second+z.second);q[p[x]].pop();}k.first=-k.first;if(k.second>0)q[p[x]].push(k);return; } signed main() {scanf("%lld",&T);while(T--){scanf("%lld%lld",&n,&t);tot=0;for(ll i=1;i<=n+1;i++){ls[i]=0;while(!q[i].empty())q[i].pop();}for(ll i=1;i<=n;i++)scanf("%lld",&w[i]);for(ll i=1,x,y;i<n;i++){scanf("%lld%lld",&x,&y);addl(x,y);addl(y,x);}++n;w[n]=1e18;addl(t,n);addl(n,t);dfs(1,0);if(q[p[1]].empty())puts("trapped");else{pair<ll,ll> w=q[p[1]].top();if(w.first>=0&&w.second>1e17)puts("escaped");else puts("trapped");}}return 0; }總結
以上是生活随笔為你收集整理的P7011-[CERC2013]Escape【堆,启发式合并】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AT4437-[AGC028C]Min
- 下一篇: 菜鸟与速卖通升级中东、北美、巴西等国际快