[Luogu P1552] [APIO2012]派遣
题面
APIO2012 派遣
Solution
这是一道左偏树的模板题,不会左偏树的可以戳这里 显然,我们可以发现对于同一颗子树,我们想让取的人尽可能便宜,如果说目前为止取的价格超过$C$,就优先把贵的人先丢掉。 因此,我们考虑用左偏树来维护这个东西。对于每一个人,我们都建一颗以价格为关键字的大根堆。考虑从下往上合并,一旦堆的元素总和超过$C$就不断弹栈,弹到合法为止。然后我们算一下$l_i*sum$,取个最大值就好。 时间复杂度$O(nlogn)$ 就酱,我们就可以把这道题切掉啦(ノ゚∀゚)ノ
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
#include<iostream> #include<cstdio> #include<vector> using namespace std; long long read() { long long x=0,f=1; char c=getchar(); while(!isdigit(c)){if(c=='-') f=-1; c=getchar();} while(isdigit(c)){x=x*10+c-'0';c=getchar();} return x*f; } const int N=100000+100; struct LST { int fa[N],son[N][2],dis[N],w[N]; long long sum[N],size[N]; inline void update(int x) { sum[x]=sum[son[x][0]]+sum[son[x][1]]+w[x]; size[x]=size[son[x][0]]+size[son[x][1]]+1; } int Merge(int x,int y) { if(x==0 or y==0) return x+y; if(w[x]>w[y]) swap(x,y); son[y][1]=Merge(x,son[y][1]); fa[son[y][1]]=y; update(y); if(dis[son[y][1]]>dis[son[y][0]]) swap(son[y][0],son[y][1]); dis[y]=dis[son[y][1]]+1; return y; } int Pop(int x) { fa[x]=Merge(son[x][0],son[x][1]); return fa[x]; } }lst; vector <int> e[N]; long long c[N],l[N],size[N],n,m; int root[N]; long long ans; void dfs(int now) { for(int i=0;i<int(e[now].size());i++) { dfs(e[now][i]); root[now]=lst.Merge(root[now],root[e[now][i]]); } while(root[now]!=0 and lst.sum[root[now]]>m) root[now]=lst.Pop(root[now]); if(root[now]!=0) ans=max(ans,l[now]*lst.size[root[now]]); } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) e[i].reserve(4); for(int i=1;i<=n;i++) { int fa=read();c[i]=read(),l[i]=read(); e[fa].push_back(i); size[i]=1; root[i]=i,lst.w[i]=lst.sum[i]=c[i],lst.size[i]=1; }
dfs(1);
printf("%lld",ans); return 0; }
|