#4306. 贪玩蓝月

题目描述

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

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

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

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

题解

考虑只加不删的话,那就是普通的 $\text{dp}$ ,即 $f[i][j]$ 表示前 $i$ 个物品,特征值的和模 $p$ 为 $j$ 的最大战斗力和,然后背包转移即可

考虑有删数的话,就上线段树分治即可,于是就又是只有加数的了,效率: $O(mplogm)$

好像有种在线的做法but我不会

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e5+5;
int m,P,b[N],U[N],V[N],G[N];
LL f[30][500],F[500];
struct O{int x,y;}a[N];
vector<O>g[N];char ch[9];
#define Ls k<<1
#define Rs k<<1|1
#define mid ((l+r)>>1)
void upd(int k,int l,int r,int L,int R,O v){
    if (L<=l && r<=R){
        g[k].push_back(v);return;
    }
    if (mid>=L) upd(Ls,l,mid,L,R,v);
    if (mid<R) upd(Rs,mid+1,r,L,R,v);
}
void qry(int k,int l,int r,int d){
    int z=g[k].size();
    for (int x,y,i=0;i<z;i++){
        x=g[k][i].x,y=g[k][i].y;
        for (int j=0;j<P;j++)
            F[(j+x)%P]=f[d][j]+y;
        for (int j=0;j<P;j++)
            f[d][j]=max(f[d][j],F[j]);
    }
    if (l==r){
        if (G[l]){
            LL v=-1;
            for (int i=U[l];i<=V[l];i++)
                v=max(v,f[d][i]);
            printf("%lld\n",v);
        }
        return;
    }
    else{
        for (int i=0;i<P;i++)
            f[d+1][i]=f[d][i];
        qry(Ls,l,mid,d+1);
        for (int i=0;i<P;i++)
            f[d+1][i]=f[d][i];
        qry(Rs,mid+1,r,d+1);
    }
}
int main(){
    cin>>m;cin>>m>>P;
    int l=m+1,r=m;
    for (int i=1;i<=m;i++){
        scanf("%s",ch);
        if (ch[0]=='I'){
            if (ch[1]=='F') b[--l]=i,
                scanf("%d%d",&a[l].x,&a[l].y);
            else b[++r]=i,
                scanf("%d%d",&a[r].x,&a[r].y);
        }
        else if (ch[0]=='Q')
            G[i]=1,scanf("%d%d",&U[i],&V[i]);
        else{
            if (ch[1]=='F') upd(1,1,m,b[l],i,a[l]),l++;
            else upd(1,1,m,b[r],i,a[r]),r--;
        }
    }
    for (int i=l;i<=r;i++) upd(1,1,m,b[i],m,a[i]);
    for (int i=1;i<P;i++) f[0][i]=-2e18;
    qry(1,1,m,0);return 0;
}

 

posted @ 2020-02-14 21:31  xjqxjq  阅读(185)  评论(0编辑  收藏  举报