洛谷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 }

 

posted @ 2018-10-17 18:27  bztMinamoto  阅读(155)  评论(0编辑  收藏  举报
Live2D