• 【洛谷P6847】Magic Tree


    题目

    题目链接:https://www.luogu.com.cn/problem/P6847
    有一棵以 (1) 为根,节点从 (1)(n) 编号的树。
    在这棵树上有许多果实,第 (j) 个果实会于第 (d_j) 天在节点 (v_j) 成熟,并且在收获后可获得 (w_j) 的果汁。
    (j) 个果实仅能在第 (d_j) 天收获。
    收获的方式是断掉这棵树的一条边,这会获得在这条边上作为儿子的那个点的子树上的当天成熟的果实的果汁。
    您要求出最多可以获得多少果汁。
    (n,m,kleq 10^5)

    思路

    (f[x][i]) 表示以点 (x) 为根的子树内,在第 (i) 天割掉 (x) 与它父亲的连边的最大收益。
    枚举 (x) 的子树 (y),有转移

    [f[x][i]=max_{jleq i}(f[y][j])+[d_x=i] imes w_x ]

    这是一个 (max) 卷积的形式,我们可以把 (x) 的贡献放到最后计算,先用线段树合并来合并 (x) 所有子树的收益,最后再加上 (x) 的贡献即可。
    时间复杂度 (O(nlog k))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=100010,LG=18;
    int n,m,k,tot,head[N],d[N],v[N],rt[N];
    
    struct edge
    {
    	int next,to;
    }e[N];
    
    void add(int from,int to)
    {
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    }
    
    struct SegTree
    {
    	int tot,lc[N*LG*4],rc[N*LG*4];
    	ll maxn[N*LG*4],lazy[N*LG*4];
    	
    	void pushdown(int x)
    	{
    		if (lazy[x])
    		{
    			if (lc[x]) maxn[lc[x]]+=lazy[x],lazy[lc[x]]+=lazy[x];
    			if (rc[x]) maxn[rc[x]]+=lazy[x],lazy[rc[x]]+=lazy[x];
    			lazy[x]=0;
    		}
    	}
    	
    	int update(int x,int l,int r,int k,ll v)
    	{
    		if (!x) x=++tot;
    		if (l==r) {	maxn[x]=v; return x; }
    		pushdown(x);
    		int mid=(l+r)>>1;
    		if (k<=mid) lc[x]=update(lc[x],l,mid,k,v);
    			else rc[x]=update(rc[x],mid+1,r,k,v);
    		maxn[x]=max(maxn[lc[x]],maxn[rc[x]]);
    		return x;
    	}
    	
    	ll query(int x,int l,int r,int ql,int qr)
    	{
    		if (ql<=l && qr>=r) return maxn[x];
    		pushdown(x);
    		int mid=(l+r)>>1; ll res=0;
    		if (ql<=mid) res=max(res,query(lc[x],l,mid,ql,qr));
    		if (qr>mid) res=max(res,query(rc[x],mid+1,r,ql,qr));
    		return res;
    	}
    	
    	int merge(int x,int y,int l,int r,ll &res1,ll &res2)
    	{
    		if (!x && !y) return 0;
    		pushdown(x); pushdown(y);
    		if (!x) { res2=max(res2,maxn[y]); maxn[y]+=res1; lazy[y]+=res1; return y; }
    		if (!y) { res1=max(res1,maxn[x]); maxn[x]+=res2; lazy[x]+=res2; return x; }
    		if (l==r)
    		{
    			res1=max(res1,maxn[x]); res2=max(res2,maxn[y]);
    			maxn[x]=max(maxn[x]+res2,maxn[y]+res1);
    			return x;
    		}
    		int mid=(l+r)>>1;
    		lc[x]=merge(lc[x],lc[y],l,mid,res1,res2);
    		rc[x]=merge(rc[x],rc[y],mid+1,r,res1,res2);
    		maxn[x]=max(maxn[lc[x]],maxn[rc[x]]);
    		return x;
    	}
    }seg;
    
    void dfs(int x)
    {
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to; ll r1=0,r2=0;
    		dfs(v);
    		rt[x]=seg.merge(rt[x],rt[v],1,m,r1,r2);
    	}
    	if (d[x])
    	{
    		ll maxn=seg.query(rt[x],1,m,1,d[x]);
    		rt[x]=seg.update(rt[x],1,m,d[x],maxn+v[x]);
    	}
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d%d",&n,&k,&m);
    	for (int i=2,x;i<=n;i++)
    	{
    		scanf("%d",&x);
    		add(x,i);
    	}
    	for (int i=1,x;i<=k;i++)
    	{
    		scanf("%d",&x);
    		scanf("%d%d",&d[x],&v[x]);
    	}
    	dfs(1);
    	cout<<seg.maxn[rt[1]];
    	return 0;
    }
    
  • 相关阅读:
    MySQL concat函数的使用
    不懂技术的人请不要对懂技术的人说这很容易
    css常用样式属性详细介绍
    堆,栈,方法区,常量池,的概念
    Springboot整合 mybatis-generator
    探秘Java中的String、StringBuilder以及StringBuffer
    微信一键登录(微信OAuth2.0)
    ActiveMQ的作用总结(应用场景及优势)以及springboot+activeMq 实战
    SpringBoot几种定时任务的实现方式 和多线程执行任务
    如何使用RedisTemplate访问Redis数据结构
  • 原文地址:https://www.cnblogs.com/stoorz/p/15048221.html
Copyright © 2020-2023  润新知