zoukankan      html  css  js  c++  java
  • Evanyou Blog 彩带

      题目传送门

    攻略

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1169  Solved: 554
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

    输出一个整数表示答案

    Sample Input

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

    Sample Output

    10

    HINT


      分析:

      网上大部分人好像都是用的$dfs$序+线段树,实际上不用那么麻烦,直接上树链剖分,加个贪心就行了。

      对于这道题,肯定要优先选取从起点(不一定是根,因为走过的路径不能重复算,所以有的路径走过以后会影响其他路径)到叶子节点权值和最大的路径,这显然就是树链剖分的轻重链/长短链(广义上)的思想,不过这里把剖分的标准换成权值和就行了。

      剖分完以后,$top[]$值等于自身的节点就是一条路径的起点,我们把它的权值和丢进大根堆里维护然后取前$k$大就行了。

      Code:

    //It is made by HolseLee on 9th Nov 2018
    //BZOJ 3252
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N=2e5+7;
    int n,m,head[N],cnte,fa[N],hson[N],top[N];
    ll a[N],siz[N],ans;
    struct Edge { int to,nxt; }e[N<<1];
    priority_queue<ll>q;
    
    inline ll read()
    {
        char ch=getchar(); ll x=0; bool flag=false;
        while( ch<'0' || ch>'9' ) {
            if( ch=='-' ) flag=true; ch=getchar();
        }
        while( ch>='0' && ch<='9' ) {
            x=x*10+ch-'0'; ch=getchar();
        }
        return flag ? -x : x;
    }
    
    inline void add(int x,int y)
    {
        e[++cnte].to=y; e[cnte].nxt=head[x];
        head[x]=cnte;
    }
    
    void dfs1(int x)
    {
        siz[x]=a[x];
        for(int i=head[x],y; i; i=e[i].nxt) {
            y=e[i].to;
            if( y==fa[x] ) continue;
            fa[y]=x; dfs1(y);
            siz[x]=max(siz[x],siz[y]+a[x]);
            if( siz[y]>siz[hson[x]] ) hson[x]=y;
        }
    }
    
    void dfs2(int x,int nowtop)
    {
        top[x]=nowtop;
        if( !hson[x] ) return;
        dfs2(hson[x],nowtop);
        for(int i=head[x],y; i; i=e[i].nxt) {
            y=e[i].to;
            if( y==fa[x] || y==hson[x] ) continue;
            dfs2(y,y);
        }
    }
    
    int main()
    {
        n=read(); m=read();
        for(int i=1; i<=n; ++i) a[i]=read();
        int x,y;
        for(int i=1; i<n; ++i) {
            x=read(), y=read();
            add(x,y), add(y,x);
        }
        dfs1(1); dfs2(1,1);
        for(int i=1; i<=n; ++i)
        if( top[i]==i ) q.push(siz[i]);
        while( (m--) && (!q.empty()) ) {
            ans+=q.top(); q.pop();
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    Mysql问题1862
    S3TC IAP15F2K61S2点亮一个发光二极管keil和stc-isp软件操作
    .NET练习计算平方根
    求一个整数以内的素数(函数实现)
    判断一个数是不是素数(函数实现)
    #号在进制输出值的作用,美化输出
    分类——决策树模型(附有决策树生成步骤)
    分类:贝叶斯分类之新闻组数据组学习(查看数据类型的方法)(环境:Pycharm)
    分类:K-近邻分类之鸢尾花数据集学习(包含数据预处理中的标准化)(环境:Pycharm)
    编写一个程序,求2~n间的素数,n由键盘输入,循环变量分别 从2到n、2到(int)sqrt(n),分别测出两个循环的所用时间。
  • 原文地址:https://www.cnblogs.com/cytus/p/9933031.html
Copyright © 2011-2022 走看看