1. 程式人生 > >[BZOJ2809][Apio2012]dispatching(左偏樹)

[BZOJ2809][Apio2012]dispatching(左偏樹)

struct int pri ros for swap 轉移 using isp

首先對於一個節點以及它的子樹,它的最優方案顯然是子樹下選最小的幾個

用左偏樹維護出每棵子樹最優方案的節點,記錄答案

然後它的這棵樹可以向上轉移給父節點,將所有子節點的左偏樹合並再維護就是父節點的最優方案

這個過程中維護答案即可

Code

#include <cstdio>
#include <algorithm>
#define ll long long
#define N 100010
using namespace std;

struct info{int to,nex;}e[N*2];
int n,m,tot,head[N],c[N],l[N],rt[N],sz[N],cnt;
ll Ans,sum[N];

namespace Lt{
	int cnt,l[N],r[N],v[N],d[N];
	int merge(int x,int y){
		if(!x||!y) return x+y;
		if(v[x]<v[y]) swap(x,y);
		r[x]=merge(r[x],y);
		if(d[r[x]]>d[l[x]]) swap(l[x],r[x]);
		d[x]=d[r[x]]+1;
		return x;
	}
	inline int tp(int x){return v[x];}
	inline void pop(int &x){x=merge(l[x],r[x]);}
}

inline void Link(int u,int v){
	e[++tot].to=v;e[tot].nex=head[u];head[u]=tot;
}

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}

void solve(int u){
	rt[u]=++cnt;
	Lt::v[cnt]=c[u];
	sz[u]=1,sum[u]=c[u];
	for(int i=head[u],v;i;i=e[i].nex){
		solve(v=e[i].to);
		sz[u]+=sz[v];
		sum[u]+=sum[v];
		rt[u]=Lt::merge(rt[u],rt[v]);
	}
	for(;sum[u]>m;){
		sum[u]-=Lt::tp(rt[u]),Lt::pop(rt[u]);
		sz[u]--;
	}
	Ans=max(Ans,sz[u]*1ll*l[u]);
}

int main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i) Link(read(),i),c[i]=read(),l[i]=read();
	solve(1);
	printf("%lld\n",Ans);
	return 0;
}

[BZOJ2809][Apio2012]dispatching(左偏樹)