• 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心


    3252: 攻略

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 339  Solved: 130
    [Submit][Status][Discuss]

    Description

    题目简述:树版[k取方格数]
     
    众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。
    今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
    “为什么你还没玩就知道每个场景的价值呢?”
    “我已经看到结局了。”

    Input

    第一行两个正整数n,k
    第二行n个正整数,表示每个场景的价值
    以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)
    保证场景1为根节点

    Output

    输出一个整数表示答案

    Sample Input

    5 2
    4 3 2 1 1
    1 2
    1 5
    2 3
    2 4

    Sample Output

    10

    HINT

    对于100%的数据,n<=200000,1<=场景价值<=2^31-1

    Source

    dfs序+线段树

    Solution

    比较好想的一道题

    首先,K次攻略,使总价值最大,显然每次攻略当前最大即可

    我们定义一个节点的Val为根到这个节点的∑val

    那么我们用线段树维护一下这个东西,每次取最大。

    考虑统计一次答案之后,这个点的价值就不存在了,那么我们只需要把这个点到根的路径上的所有点的val在它的子树中减去即可

    每个点只减一次就可以了....

    所以时间复杂度还是$O(nlogn)$的

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    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;
    }
    #define MAXN 200010
    #define LL long long
    int N,K;
    bool visit[MAXN];
    LL sumV[MAXN],val[MAXN];
    struct EdgeNode{int next,to;}edge[MAXN<<1];
    int head[MAXN],cnt=1,fa[MAXN]; 
    void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    void InsertEdge(int u,int v) {fa[v]=u; AddEdge(u,v); AddEdge(v,u);}
    int pl[MAXN],pr[MAXN],dfn,pre[MAXN];
    void DFS(int now,int last)
    {
        pl[now]=++dfn; pre[dfn]=now;
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].to!=last)
                sumV[edge[i].to]=sumV[now]+val[edge[i].to],DFS(edge[i].to,now);
        pr[now]=dfn;
    }
    struct SegmentTreeNode{int l,r,maxp; LL maxx,tag;}tree[MAXN<<2];
    int Maxp(SegmentTreeNode ls,SegmentTreeNode rs) {return ls.maxx>rs.maxx? ls.maxp:rs.maxp;}
    void Update(int now) 
    {
        tree[now].maxx=max(tree[now<<1].maxx,tree[now<<1|1].maxx);
        tree[now].maxp=Maxp(tree[now<<1],tree[now<<1|1]);
    }
    void BuildTree(int now,int l,int r)
    {
        tree[now].l=l; tree[now].r=r;
        if (l==r) {tree[now].maxx=sumV[pre[l]]; tree[now].maxp=l; return;}
        int mid=(l+r)>>1;
        BuildTree(now<<1,l,mid); BuildTree(now<<1|1,mid+1,r);
        Update(now);
    }
    void PushDown(int now)
    {
        if (tree[now].l==tree[now].r || !tree[now].tag) return;
        LL tag=tree[now].tag; tree[now].tag=0;
        tree[now<<1].maxx+=tag; tree[now<<1|1].maxx+=tag;
        tree[now<<1].tag+=tag; tree[now<<1|1].tag+=tag;
    }
    void Change(int now,int L,int R,int val)
    {
        PushDown(now);
        int l=tree[now].l,r=tree[now].r;
        if (L<=l && R>=r) {tree[now].maxx+=val; tree[now].tag+=val; return;}
        int mid=(l+r)>>1;
        if (L<=mid) Change(now<<1,L,R,val);
        if (R>mid) Change(now<<1|1,L,R,val);
        Update(now);
    }
    int main()
    {
        N=read(); K=read();
        for (int i=1; i<=N; i++) val[i]=read();
        for (int x,y,i=1; i<=N-1; i++) x=read(),y=read(),InsertEdge(x,y);
        sumV[1]=val[1]; DFS(1,0);
    //    for (int i=1; i<=N; i++)
    //        printf("ID=%d   [%d , %d] %d %d
    ",pre[i],pl[pre[i]],pr[pre[i]],val[pre[i]],sumV[pre[i]]);
        LL ans=0;
        BuildTree(1,1,N);
        for (int i=1; i<=K; i++)
            {
    //            printf("NOW=%d   :  %d , %d
    ",i,tree[1].maxx,tree[1].maxp);
                if (tree[1].maxx>0) ans+=tree[1].maxx; else break;
                for (int x=pre[tree[1].maxp]; !visit[x]&&x; x=fa[x])
                    visit[x]=1,Change(1,pl[x],pr[x],-val[x]); 
            }
        printf("%lld
    ",ans);
        return 0;
    }

    第一次明白攻略组的意思....大概是看刀剑的时候吧/....

  • 相关阅读:
    局部 与 整体 修正 逐渐逼近
    en-zh(社会问题)social problems
    单调性 [1 + 1 / (n)]^n
    en-zh(科学技术)science and technology
    mysql函数之截取字符串
    看数据库的文件大小 MySQL Binlog日志的生成和清理规则
    Brouwer不动点
    布尔巴基学派
    量子杨-Baxter方程新解系的一般量子偶构造_爱学术 https://www.ixueshu.com/document/f3385115a33571aa318947a18e7f9386.html
    COMSOL
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5850026.html
Copyright © 2020-2023  润新知