zoukankan      html  css  js  c++  java
  • BZOJ 3252题解(贪心+dfs序+线段树)

    题面

    传送门

    分析

    此题做法很多,树形DP,DFS序+线段树,树链剖分都可以做
    这里给出DFS序+线段树的代码
    我们用线段树维护到根节点路径上节点权值之和的最大值,以及取到最大值的节点编号x
    每次从根节点走到x,将点归0,再把最大值累加
    然而,修改操作怎么做呢?
    这里当然可以树剖,但是还有代码量更小的做法
    从x往父亲跳,每次将子树中的节点值都-v(v为当前节点的权值,当前节点权值变为0,从根到子树中的节点必须经过它,所有路径值之和-v)
    然后加一个标记mark,如果这个节点之前被清零过就不用再跳了

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 200005
    using namespace std;
    int n,k;
    struct edge{
        int from;
        int to;
        int next;
    }E[maxn<<1];
    int size=0;
    int head[maxn];
    void add_edge(int u,int v){
        size++;
        E[size].from=u;
        E[size].to=v;
        E[size].next=head[u];
        head[u]=size;
    }
    
    int cnt=0;
    int l[maxn],r[maxn],hash[maxn],mark[maxn];
    //l,r为dfs序中子树的区间范围
    //hash[i]表示dfs序中的第i个节点编号
    //mark的含义见上方分析
    long long a[maxn];
    long long sum[maxn];
    int fa[maxn];
    void dfs(int x,int pa){
        sum[x]=sum[pa]+a[x];
        l[x]=++cnt;
        hash[cnt]=x;
        fa[x]=pa;
        for(int i=head[x];i;i=E[i].next){
            int y=E[i].to;
            if(y!=pa){
                dfs(y,x);
            } 
        }   
        r[x]=cnt;
    }
    
    struct node{
        int l;
        int r;
        long long v;
        long long mark;
        int point;
    }tree[maxn<<2];
    void push_up(int pos){
        if(tree[pos<<1].v>tree[pos<<1|1].v){
            tree[pos].v=tree[pos<<1].v;
            tree[pos].point=tree[pos<<1].point;
        }else{
            tree[pos].v=tree[pos<<1|1].v;
            tree[pos].point=tree[pos<<1|1].point;
        }
    }
    void build(int l,int r,int pos){
        tree[pos].l=l;
        tree[pos].r=r;
        tree[pos].v=0;
        tree[pos].mark=0;
        if(l==r){
            tree[pos].v=sum[hash[l]];
            tree[pos].point=hash[l];
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,pos<<1);
        build(mid+1,r,pos<<1|1);
        push_up(pos);
    }
    void push_down(int pos){
        if(tree[pos].mark){
            tree[pos<<1].v+=tree[pos].mark;
            tree[pos<<1].mark+=tree[pos].mark;
            tree[pos<<1|1].v+=tree[pos].mark;
            tree[pos<<1|1].mark+=tree[pos].mark;
            tree[pos].mark=0;
        }
    }
    void update(int L,int R,int v,int pos){
        if(L<=tree[pos].l&&R>=tree[pos].r){
            tree[pos].v+=v;
            tree[pos].mark+=v;
            return; 
        }
        push_down(pos);
        int mid=(tree[pos].l+tree[pos].r)>>1;
        if(L<=mid) update(L,R,v,pos<<1);
        if(R>mid) update(L,R,v,pos<<1|1);
        push_up(pos);
    }
    void change(int x){
        while(x){
            if(mark[x]) break;
            mark[x]=1;
            update(l[x],r[x],-a[x],1);//子树的值-1
            x=fa[x];//向上跳
        }
    }
    int main(){
    //  freopen("input.txt","r",stdin);
        int u,v;
        scanf("%d %d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        for(int i=1;i<n;i++){
            scanf("%d %d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs(1,0);
        build(1,n,1);
        long long ans=0;
        for(int i=1;i<=k;i++){
            ans=ans+tree[1].v;
            change(tree[1].point);
        }
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    Ruby向Java发起挑战,红色风暴来了吗?
    学习语义网的好书
    Joel给计算机系学生们七条免费的建议
    ruby rails: 一个高开发效率的web开发框架
    推荐:《真正的执行》
    每个java程序员都应该看看Jakarta Commons
    上海IT俱乐部论坛开通了!
    重构的三个层次
    一些蔡志忠先生的漫画书!
    pythonchanllenge: 解决迷题,非常有趣的学习python的方式
  • 原文地址:https://www.cnblogs.com/birchtree/p/9858038.html
Copyright © 2011-2022 走看看