1. 程式人生 > >洛谷P1552 [APIO2012]派遣(左偏樹)

洛谷P1552 [APIO2012]派遣(左偏樹)

傳送門

 

做這題的時候現學了一波左偏樹2333(好吧其實是當初打完板子就給忘了)

不難發現肯定是選子樹裡權值最小的點且選得越多越好

但如果在每一個點維護一個小根堆,我們得一直找知道權值大於m為止,時間會炸

於是我們對每一個點維護一個大根堆,一直pop直到堆裡總的權值小於m為止,此時堆裡的元素個數就是總共的人數

不難發現每一個人最多隻會被pop一次,於是時間複雜度就是$O(n\ logn)$

左偏樹合併寫錯了竟然還能有67分……

 1 //minamoto
 2 #include<bits/stdc++.h>
 3 #define ll long long
 4
using namespace std; 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 6 char buf[1<<21],*p1=buf,*p2=buf; 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 8 inline int read(){ 9 #define num ch-'0' 10
char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch=='-')&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 const int N=1e5+5; 19 int head[N],Next[N],ver[N],tot;
20 inline void add(int u,int v){ 21 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 22 } 23 int val[N],rt[N],L[N],R[N],a[N],d[N],sz[N],n,m;ll sum[N],ans; 24 int merge(int x,int y){ 25 if(!x||!y) return x+y; 26 if(val[x]<val[y]) swap(x,y); 27 R[x]=merge(R[x],y); 28 if(d[R[x]]>d[L[x]]) swap(L[x],R[x]); 29 d[x]=d[R[x]]+1;return x; 30 } 31 void dfs(int u){ 32 sz[u]=1,sum[u]=val[u],rt[u]=u; 33 for(int i=head[u];i;i=Next[i]){ 34 int v=ver[i];dfs(v); 35 sz[u]+=sz[v],sum[u]+=sum[v],rt[u]=merge(rt[u],rt[v]); 36 } 37 while(sum[u]>m&&sz[u]){ 38 sum[u]-=val[rt[u]],--sz[u],rt[u]=merge(L[rt[u]],R[rt[u]]); 39 } 40 cmax(ans,1ll*sz[u]*a[u]); 41 } 42 int main(){ 43 // freopen("testdata.in","r",stdin); 44 n=read(),m=read(); 45 for(int i=1;i<=n;++i){ 46 int fa=read();val[i]=read(),a[i]=read(); 47 add(fa,i); 48 } 49 dfs(1); 50 printf("%lld\n",ans); 51 return 0; 52 }