【左偏树】[APIO2012]派遣
题意可真的是有毒
第一眼树形背包可做?(反正我没用树形背包打过,边上巨佬打的背包似乎没拿分)
后来发现可以贪心搞,我们先把一个节点所有的儿子都取进去,之后不行的话再从大的开始拿走就好了
问题就变成了了如何快速维护各个节点子树中的最大值,优先队列就好了!
关键是还要资瓷合并,pb_ds库就好了,手打左偏树就好了
有人说这是裸题...但我真的看了好久...肯定是我tcl
1 #include<bits/stdc++.h> 2 #define int long long 3 #define writeln(x) write(x),puts("") 4 #define writep(x) write(x),putchar(' ') 5 using namespace std; 6 inline int read(){ 7 int ans=0,f=1;char chr=getchar(); 8 while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();} 9 while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} 10 return ans*f; 11 }void write(int x){ 12 if(x<0) putchar('-'),x=-x; 13 if(x>9) write(x/10); 14 putchar(x%10+'0'); 15 }const int M = 2e5+5; 16 int n,m; 17 int son[M][2],fa[M],dis[M],val[M],a[M],b[M],ans; 18 int head[M],ver[M<<1],nxt[M<<1],tot,sum[M],sz[M]; 19 #define ls son[x][0] 20 #define rs son[x][1] 21 inline void cmax(int &x,int y){if(x<y) x=y;} 22 inline void add(int x,int y){ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;} 23 int Merge(int x,int y){ 24 if(!x||!y) return x|y; 25 if(val[x]<val[y]) swap(x,y); 26 rs=Merge(rs,y); 27 if(dis[ls]<dis[rs]) swap(ls,rs); 28 fa[ls]=fa[rs]=fa[x]=x; 29 dis[x]=dis[rs]+1; 30 return x; 31 } 32 signed main(){ 33 dis[0]=-1; 34 n=read(),m=read(); 35 for(register long x,y,i=1;i<=n;++i) 36 fa[i]=i,sz[i]=1,x=read(),val[i]=sum[i]=read(),b[i]=read(),add(x,i); 37 for(register long x=n;x>=1;--x){ 38 for(register long i=head[x];i;i=nxt[i]){ 39 int y=ver[i]; 40 fa[x]=fa[y]=Merge(fa[x],fa[y]); 41 sum[x]+=sum[y]; 42 sz[x]+=sz[y] ; 43 }while(sum[x]>m){ 44 sum[x]-=val[fa[x]]; 45 --sz[x]; 46 fa[x]=Merge(son[fa[x]][0],son[fa[x]][1]); 47 }cmax(ans,b[x]*sz[x]); 48 }printf("%lld",ans); 49 return 0; 50 }