zoukankan      html  css  js  c++  java
  • [Bzoj3252]攻略(dfs序+线段树)

    Description

    题目链接

    Solution

    可以想到,每次肯定是拿最大价值为最优

    考虑改变树上一个点的值,只会影响它的子树,也就是dfs序上的一个区间,

    于是可以以dfs序建线段树,这样就变成区间问题了

    Code

    #include <cstdio>
    #include <algorithm>
    #define MID int mid=(l+r)>>1,ls=id<<1,rs=id<<1|1
    #define ll long long
    #define N 200010
    using namespace std;
    
    struct xds{ll x,tag;}T[N<<2];
    struct info{int to,nex;}e[N<<1];
    int n,k,tot,head[N],val[N],dfn[N],bel[N],fa[N],R[N],x;
    ll Ans,sum[N];
    bool vis[N];
    
    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 Link(int u,int v){
    	e[++tot].nex=head[u];e[tot].to=v;head[u]=tot;
    }
    
    void dfs(int u){
    	bel[dfn[u]=++tot]=u;sum[tot]=sum[dfn[fa[u]]]+val[u];
    	for(int i=head[u];i;i=e[i].nex){
    		int v=e[i].to;
    		if(v==fa[u]) continue;
    		fa[v]=u;
    		dfs(v);
    	}
    	R[u]=tot;
    }
    
    void build(int l,int r,int id){
    	if(l==r){T[id].x=sum[l];return;}
    	MID;
    	build(l,mid,ls);
    	build(mid+1,r,rs);
    	T[id].x=max(T[ls].x,T[rs].x);
    }
    
    void pushdown(int id){
    	ll &tag=T[id].tag;
    	if(!tag) return;
    	int ls=id<<1,rs=id<<1|1;
    	T[ls].x+=tag;T[ls].tag+=tag;
    	T[rs].x+=tag;T[rs].tag+=tag;
    	tag=0;
    }
    
    void Find(int l,int r,int id){
    	if(l==r){x=bel[l];return;}
    	pushdown(id);
    	MID;
    	if(T[ls].x>T[rs].x) Find(l,mid,ls);
    	else Find(mid+1,r,rs);
    	T[id].x=max(T[ls].x,T[rs].x);
    }
    
    void Modify(int l,int r,int id,int ql,int qr,int x){
    	if(l>=ql&&qr>=r){
    		T[id].x+=x;T[id].tag+=x;return;
    	}
    	pushdown(id);
    	MID;
    	if(ql<=mid) Modify(l,mid,ls,ql,qr,x);
    	if(qr>mid) Modify(mid+1,r,rs,ql,qr,x);
    	T[id].x=max(T[ls].x,T[rs].x);
    }
    
    int main(){
    	n=read(),k=read();
    	for(int i=1;i<=n;++i) val[i]=read();
    	for(int i=1;i<n;++i){
    		int u=read(),v=read();
    		Link(u,v);Link(v,u);
    	}
    	tot=0;dfs(1);
    	build(1,n,1);
    	while(k--)
    	{
    		Ans+=T[1].x;
    		Find(1,n,1);
    		for(;x&&!vis[x];vis[x]=1,x=fa[x]) Modify(1,n,1,dfn[x],R[x],-val[x]);
    	}
    	printf("%lld
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    java事件处理(贪吃蛇)
    九九乘法表
    使用文件包含指令include
    jsp页面的基本构成
    软件测试博客

    成功职业女性处世的10大秘诀
    再见啦,冬冬妹
    网摘——杜晓眼眼中的尹珊珊:什么都要,什么都要得到
    网摘——事关“工程师思维”
  • 原文地址:https://www.cnblogs.com/void-f/p/8676378.html
Copyright © 2011-2022 走看看