• [BZOJ2809][Apio2012]dispatching(左偏树)


    首先对于一个节点以及它的子树,它的最优方案显然是子树下选最小的几个

    用左偏树维护出每棵子树最优方案的节点,记录答案

    然后它的这棵树可以向上转移给父节点,将所有子节点的左偏树合并再维护就是父节点的最优方案

    这个过程中维护答案即可

    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
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    Go语言中DateTime知识点
    Go语言中的string知识点
    Go语言中的Iota
    Go语言的通道(2)-缓冲通道
    Go语言的通道(1)-无缓冲通道
    Go语言协程
    设计一个好的通用组件
    Windows服务器【由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作】问题调查
    Go语言的并发
    SCSS 中的 &::before 和 &::after
  • 原文地址:https://www.cnblogs.com/void-f/p/9168947.html
Copyright © 2020-2023  润新知