• bzoj3252


    3252: 攻略

    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
     
    sol:显然每次都取最大的那条链一定是最优的(废话,难在怎么维护,每个点维护它到根的点权和,发现一个点被改掉以后整个子树都会被修改,所以搞出dfs序之后线段树上搞搞就好了
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
      ll s=0; bool f=0; char ch=' ';
      while(!isdigit(ch)) {f|=(ch=='-'); ch=getchar();}
      while(isdigit(ch)) {s=(s<<3)+(s<<1)+(ch^48); ch=getchar();}
      return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
      if(x<0) {putchar('-'); x=-x;}
      if(x<10) {putchar(x+'0'); return;}
      write(x/10); putchar((x%10)+'0');
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=200005,M=400005;
    int n,m,fa[N],clk=0,inc[N],ouc[N],ref[N];
    ll a[N],val[N],ans=0;
    bool del[N];
    int tot=0,Next[M],to[M],head[N];
    #define fi first
    #define se second
    #define Mp make_pair
    struct Node
    {
      pair<ll,ll> mx;
      ll lz;
    }T[N<<2];
    #define c1 (x<<1)
    #define c2 (x<<1|1)
    inline void Link(int x,int y)
    {
      Next[++tot]=head[x]; to[tot]=y; head[x]=tot;
    }
    inline void Dfs(int x,int fat)
    {
      int e;
      fa[x]=fat; val[x]=val[fat]+a[x]; inc[x]=++clk; ref[clk]=x;
      for(e=head[x];e;e=Next[e]) Dfs(to[e],x);
      ouc[x]=clk;
    }
    inline void PushUp(int x)
    {
      T[x].mx=max(T[c1].mx,T[c2].mx);
    }
    inline void PushDown(int x)
    {
      if(!T[x].lz) return;
      T[c1].mx.fi+=T[x].lz; T[c1].lz+=T[x].lz;
      T[c2].mx.fi+=T[x].lz; T[c2].lz+=T[x].lz;
      T[x].lz=0;
    }
    inline void Build(int x,int l,int r)
    {
      if(l==r){T[x].mx=Mp(val[ref[l]],l); return;}
      int mid=(l+r)>>1;
      Build(c1,l,mid); Build(c2,mid+1,r);
      PushUp(x);
    }
    inline void Updata(int x,int l,int r,int ql,int qr,ll val)
    {
      if(l==ql&&r==qr)
      {
        T[x].mx.fi+=val; T[x].lz+=val; return;
      }
      PushDown(x);
      int mid=(l+r)>>1;
      if(qr<=mid) Updata(c1,l,mid,ql,qr,val);
      else if(ql>mid) Updata(c2,mid+1,r,ql,qr,val);
      else Updata(c1,l,mid,ql,mid,val),Updata(c2,mid+1,r,mid+1,qr,val);
      PushUp(x);
    }
    int main()
    {
      freopen("bzoj3252.in","r",stdin);
        int i,x,y;
        R(n); R(m);
      for(i=1;i<=n;i++) R(a[i]);
        for(i=1;i<n;i++) {R(x); R(y); Link(x,y);}
      Dfs(1,0);
      // for(i=1;i<=n;i++) cout<<ref[i]<<' '; putchar('
    ');
      Build(1,1,n);
      for(i=1;i<=m;i++)
      {
        ans+=T[1].mx.fi;
        x=ref[T[1].mx.se];
        // cout<<"ans="<<ans<<' '<<"now="<<x<<endl;
        while((!del[x])&&x)
        {
          Updata(1,1,n,inc[x],ouc[x],-1*a[x]); del[x]=1; x=fa[x];
          // cout<<x<<' '<<inc[x]<<' '<<ouc[x]<<' '<<a[x]<<endl;
        }
      }
      Wl(ans);
      return 0;
    }
    /*
    input
    5 2
    4 3 2 1 1
    1 2
    1 5
    2 3
    2 4
    output
    10
    */
    View Code
  • 相关阅读:
    Qt C++中的关键字explicit——防止隐式转换(也就是Java里的装箱),必须写清楚
    有栖川有栖《马来铁道之谜》读后感
    Qt多国语言QT_TR_NOOP和QT_TRANSLATE_NOOP
    Qt调用VC++生成的动态链接库
    QTabWidget添加自定义样式
    Qt跨线程信号和槽的连接(默认方式是直连和队列的折中)
    OO五大原则
    《Head First Python》学习笔记03 异常处理
    使用Qt实现MDI风格的主窗体
    Qt中文乱码问题(比较清楚,同一个二进制串被解释成不同的语言)
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/11234513.html
Copyright © 2020-2023  润新知