日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P7011-[CERC2013]Escape【堆,启发式合并】

發布時間:2023/12/3 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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^51n2×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【堆,启发式合并】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。