zoukankan      html  css  js  c++  java
  • 【线段树分治 01背包】loj#6515. 「雅礼集训 2018 Day10」贪玩蓝月

     考试时候怎么就是没想到线段树分治呢?

    题目描述

    《贪玩蓝月》是目前最火爆的网页游戏。在游戏中每个角色都有若干装备,每件装备有一个特征值 $w$ 和一个战斗力 $v$ 。在每种特定的情况下,你都要选出特征值的和对 $ m MOD$ 取模后在一段范围内的装备,而角色死亡时自己的装备会爆掉。每个角色的物品槽可以看成一个双端队列,得到的装备会被放在两端,自己的装备爆掉也会在两端被爆。

    现在我们有若干种事件和询问,如下所示:

    • IF w v:在前端加入一件特征值为 $w$ 战斗力为 $v$ 的装备
    • IG w v:在后端加入一件特征值为 $w$ 战斗力为 $v$ 的装备
    • DF:删除最前端的装备
    • DG:删除最后端的装备
    • QU l r:在当前的装备中选取若干装备,他们的和对 $ m MOD$ 取模后在 $[l, r]$ 中,使得这些装备的战斗力之和最大

    为了锻炼你的水平,请尽量使用在线做法。


    题目分析

    做法一:线段树分治

    考虑一下w,v强制在线的做法。

    注意到这个在线是个“半在线”:因为虽然w,v是被加密过的,但是操作种类是可见的。那么就可以预先处理处每一个物品的存在时间区间,因此这样对操作进行线段树分治就是个离线问题了。

     1 #include<bits/stdc++.h>
     2 typedef long long ll;
     3 const int maxn = 50035;
     4 
     5 int m,p,tag;
     6 ll ans[maxn];
     7 struct QRs
     8 {
     9     char opt[5];
    10     int l,r;
    11 }qr[maxn];
    12 struct Opt
    13 {
    14     int s,t,w,v;
    15     Opt(int a=0, int b=0, int c=0, int d=0):s(a),t(b),w(c),v(d) {}
    16 }rec[maxn];
    17 struct node
    18 {
    19     ll f[503],g[503];
    20     void init()
    21     {
    22         memset(f, -0x3f3f3f3f, sizeof f), f[0] = 0;
    23     }
    24     void update(int w, int v)
    25     {
    26         for (int i=0; i<p; i++) g[i] = f[i];
    27         for (int i=0; i<p; i++)        //x+w=i
    28             f[i] = std::max(f[i], g[(i-w+p)%p]+v);
    29     }
    30     ll query(int l, int r)
    31     {
    32         ll ret = -1;
    33         for (int i=l; i<=r; i++) ret = std::max(f[i], ret);
    34         return ret;
    35     }
    36 }sta;
    37 typedef std::vector<Opt> vec;
    38 std::deque<int> deq;
    39 vec opt;
    40 
    41 int read()
    42 {
    43     char ch = getchar();
    44     int num = 0, fl = 1;
    45     for (; !isdigit(ch); ch=getchar())
    46         if (ch=='-') fl = -1;
    47     for (; isdigit(ch); ch=getchar())
    48         num = (num<<1)+(num<<3)+ch-48;
    49     return num*fl;
    50 }
    51 void solve(int l, int r, vec opt, node sta)
    52 {
    53     vec L,R;
    54     int mid = (l+r)>>1;
    55     for (int i=0, mx=opt.size(); i<mx; i++)
    56     {
    57         int s = opt[i].s, t = opt[i].t;
    58         if (s <= l&&r <= t) sta.update(opt[i].w, opt[i].v);
    59         else{
    60             if (s <= mid) L.push_back(opt[i]);
    61             if (t > mid) R.push_back(opt[i]);
    62         }
    63     }
    64     if (l==r){
    65         if (qr[l].opt[0]=='Q') ans[l] = sta.query(qr[l].l, qr[l].r);
    66     }else solve(l, mid, L, sta), solve(mid+1, r, R, sta);
    67 }
    68 int main()
    69 {
    70     scanf("%*d"), m = read(), p = read();
    71     for (int i=1, tmp; i<=m; i++)
    72     {
    73         scanf("%s",qr[i].opt);
    74         if (qr[i].opt[0]=='I'){
    75             qr[i].l = read()%p, qr[i].r = read(), ++tag;
    76             if (qr[i].opt[1]=='F') deq.push_front(tag);
    77             else deq.push_back(tag);
    78             opt.push_back(Opt(i, m, qr[i].l, qr[i].r));
    79         }
    80         if (qr[i].opt[0]=='Q')
    81             qr[i].l = read(), qr[i].r = read();
    82         if (qr[i].opt[0]=='D'){
    83             if (qr[i].opt[1]=='F')
    84                 tmp = deq.front(), deq.pop_front();
    85             else tmp = deq.back(), deq.pop_back();
    86             opt[tmp-1].t = i-1;
    87         }
    88     }
    89     sta.init();
    90     solve(1, m, opt, sta);
    91     for (int i=1; i<=m; i++)
    92         if (qr[i].opt[0]=='Q') printf("%lld
    ",ans[i]);
    93     return 0;
    94 }

    做法二:思维题  栈  启发式

    可能要先咕着

  • 相关阅读:
    To the Virgins, to Make Much of Time
    瓦尔登湖
    贪心算法
    R语言实战 —— 常见问题解决方法
    R语言实战(四)—— 基本数据管理
    R语言实战(三)——模拟随机游走数据
    Vim——回顾整理
    Clion下载安装使用教程(Win+MinGW)
    【ACM】孪生素数问题
    【ACM】一种排序
  • 原文地址:https://www.cnblogs.com/antiquality/p/10392329.html
Copyright © 2011-2022 走看看