zoukankan      html  css  js  c++  java
  • 【贪心】 BZOJ 3252:攻略

    3252: 攻略

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 261  Solved: 90
    [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


      很容易知道贪心策略:每次选价值最高的叶子节点

      但是貌似很难搞的样子

      朴素算法应该是n^2的样子。。

      O(n)显然不太好搞。。

      所以大约优化完后是O(nlgn)左右的复杂度。。

      有两种logn的方法

      1.黄学长的堆。。自行百度。。我只能说代码完全看不懂。。

      2.DFS序+线段树

      DFS处理出一个点管辖的所有点的DFS序。

      然后线段树添加,每次删除。

      

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<vector>
      6 
      7 #define maxn 200001
      8 
      9 using namespace std;
     10 
     11 vector<int>graph[maxn];
     12 
     13 int rev[maxn],in[maxn],father[maxn],dfn[maxn],last[maxn],tot=0;
     14 
     15 long long a[maxn];
     16 
     17 bool vis[maxn];
     18 
     19 struct tr{
     20     int l,r,ps;
     21     long long num,tag;
     22 }tree[maxn*6];
     23 
     24 long long read()
     25 {
     26     long long x=0;char ch=getchar();
     27     while(ch<'0'||ch>'9')ch=getchar();
     28     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
     29     return x;
     30 }
     31 
     32 void DFS(int poi)
     33 {
     34     dfn[poi]=++tot;
     35     rev[tot]=poi;
     36     for(int i=graph[poi].size()-1;i>=0;i--)
     37     {
     38         int u=graph[poi][i];
     39         DFS(u);
     40     }
     41     last[poi]=tot;
     42 }
     43 
     44 void psh(int poi)
     45 {
     46     if(tree[poi].tag&&tree[poi].l!=tree[poi].r)
     47     {
     48     tree[poi<<1].tag+=tree[poi].tag;
     49     tree[(poi<<1)|1].tag+=tree[poi].tag;
     50     tree[poi<<1].num+=tree[poi].tag;
     51     tree[(poi<<1)|1].num+=tree[poi].tag;
     52     tree[poi].tag=0;
     53     }
     54 }
     55 
     56 void update(int num,int l,int r,long long d)
     57 {
     58     psh(num);
     59     if(tree[num].l==l&&tree[num].r==r)
     60     {
     61         tree[num].num+=d;
     62         tree[num].tag+=d;
     63         return;
     64     }
     65     int mid=(tree[num].l+tree[num].r)>>1;
     66     if(mid>=r)update(num<<1,l,r,d);
     67     else if(l>mid)update((num<<1)|1,l,r,d);
     68     else update(num<<1,l,mid,d),update((num<<1)|1,mid+1,r,d);
     69     if(tree[num].l==tree[num].r)return;
     70     if(tree[num<<1].num>tree[(num<<1)|1].num){tree[num].num=tree[num<<1].num,tree[num].ps=tree[num<<1].ps;}
     71     if(tree[(num<<1)|1].num>=tree[num<<1].num){tree[num].num=tree[(num<<1)|1].num,tree[num].ps=tree[(num<<1)|1].ps;}
     72 }
     73 
     74 void build(int num,int l,int r)
     75 {
     76     if(l==r)
     77     {
     78         tree[num].l=tree[num].r=l;
     79         tree[num].ps=l;
     80         return;
     81     }
     82     int mid=(l+r)>>1;
     83     build(num<<1,l,mid);
     84     build((num<<1)|1,mid+1,r);
     85     tree[num].l=l,tree[num].r=r;
     86     tree[num].ps=tree[(num<<1)|1].ps;
     87 }
     88 
     89 int main()
     90 {
     91     long long ans=0;
     92     int n,k;
     93     n=read(),k=read();
     94     for(int i=1;i<=n;i++)a[i]=read();
     95     for(int i=1;i<n;i++)
     96     {
     97         int u,v;
     98     u=read();v=read();
     99     graph[u].push_back(v);
    100     father[v]=u;
    101     }
    102     
    103     father[1]=0;
    104     
    105     DFS(1);
    106     build(1,1,n);
    107     
    108     for(int i=1;i<=n;i++)
    109         update(1,dfn[i],last[i],a[i]);
    110 
    111     while(k--)
    112     {
    113     psh(1);
    114     ans+=tree[1].num;
    115     int u=rev[tree[1].ps];
    116     while(u&&!vis[u])
    117     {
    118         vis[u]=1;
    119         update(1,dfn[u],last[u],-a[u]);
    120         u=father[u];
    121     }
    122     }
    123     printf("%lld",ans);
    124     return 0;
    125 }
    View Code

      (死于太久没打tag。。)

      

  • 相关阅读:
    theme-windowAnimationStyle 动画设置
    Perl中的正则表达式
    repo sync下载脚本
    Virtual Box创建共享目录
    ubuntu下安装jdk
    adb logcat 命令
    如何提高上传带宽
    Ubuntu安装dos2unix工具
    Android打Path的方法
    Ubuntu快捷键
  • 原文地址:https://www.cnblogs.com/tuigou/p/4848532.html
Copyright © 2011-2022 走看看