1. 程式人生 > >【LibreOJ】#6396. 「THUPC2018」弗雷茲的玩具商店 / Toyshop 線段樹+完全背包

【LibreOJ】#6396. 「THUPC2018」弗雷茲的玩具商店 / Toyshop 線段樹+完全背包

給定 註意 線段 fin names AI 循環 else https

【題目】#6396. 「THUPC2018」弗雷茲的玩具商店 / Toyshop
【題意】給定一個長度為n的物品序列,每個物品有價值、不超過m的重量。要求支持以下三種操作:1.物品價值區間加減,2.物品重量區間加(超過m部分取模),3.區間物品求解容量為m的完全背包數組。\(n \leq 2*10^5,m \leq 60,Q \leq 3*10^4\)
【算法】線段樹+完全背包
顯然,每個重量只需要保留價值最大的物品。

然後就很簡單了,線段樹每個維護一個數組c[x]表示重量x的最大價值,區間循環和區間加減,每次詢問將區間m個重量的最大價值拿出來做完全背包。註意初始化為-inf(否則相當於有價值為0的物品,之後進行物品價值加減後就會幹擾答案了)。

復雜度\(O(nm\ \ log\ \ n+m^2)\)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define lowbit(x) (x&-x)
bool isdigit(char c){return c>=‘0‘&&c<=‘9‘;}
int read(){
    int s=0,t=1;char c;
    while(!isdigit(c=getchar()))if(c==‘-‘)t=-1;
    do{s=s*10+c-‘0‘;}while(isdigit(c=getchar()));
    return s*t;
}   
using namespace std;
const int maxn=200010,M=70;
const ll inf=1ll<<60;
int n,m,w[maxn],v[maxn];
ll C[M],f[M],D[M];//chong fu X
struct tree{int l,r,w_delta,v_delta;ll c[M];}t[maxn*4];
ll max(ll a,ll b){return a<b?b:a;}
void up(int k){
    for(int i=1;i<=m;i++)t[k].c[i]=max(t[k<<1].c[i],t[k<<1|1].c[i]);
}
void w_modify(int k,int x){
    t[k].w_delta+=x;
    for(int i=1;i<=m;i++)D[(i-1+x)%m+1]=t[k].c[i];
    for(int i=1;i<=m;i++)t[k].c[i]=D[i];
}
void v_modify(int k,int x){
    
    t[k].v_delta+=x;
    for(int i=1;i<=m;i++)t[k].c[i]+=x;
}
void down(int k){
    if(t[k].w_delta){
        w_modify(k<<1,t[k].w_delta);w_modify(k<<1|1,t[k].w_delta);
        t[k].w_delta=0;
    }
    if(t[k].v_delta){
        v_modify(k<<1,t[k].v_delta);v_modify(k<<1|1,t[k].v_delta);
        t[k].v_delta=0;
    }
}
void build(int k,int l,int r){
    for(int i=1;i<=m;i++)t[k].c[i]=-inf;//-inf no influense
    t[k].l=l;t[k].r=r;
    if(l==r){t[k].c[w[l]]=v[l];return;}//return
    int mid=(l+r)>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    up(k);
}
void w_fix(int k,int l,int r,int x){
    if(l<=t[k].l&&t[k].r<=r){w_modify(k,x);return;}
    down(k);//
    int mid=(t[k].l+t[k].r)>>1;
    if(l<=mid)w_fix(k<<1,l,r,x);
    if(r>mid)w_fix(k<<1|1,l,r,x);
    up(k);
}
void v_fix(int k,int l,int r,int x){
    if(l<=t[k].l&&t[k].r<=r){v_modify(k,x);return;}
    down(k);//
    int mid=(t[k].l+t[k].r)>>1;
    if(l<=mid)v_fix(k<<1,l,r,x);
    if(r>mid)v_fix(k<<1|1,l,r,x);
    up(k);
}
void query(int k,int l,int r){
    if(l<=t[k].l&&t[k].r<=r){
        for(int i=1;i<=m;i++)C[i]=max(C[i],t[k].c[i]);
        return;//return
    }
    down(k);//use down
    int mid=(t[k].l+t[k].r)>>1;
    if(l<=mid)query(k<<1,l,r);
    if(r>mid)query(k<<1|1,l,r);
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)w[i]=read();
    for(int i=1;i<=n;i++)v[i]=read();
    build(1,1,n);
    int Q=read();
    while(Q--){
        int kind=read(),l=read(),r=read();
        if(kind==1){
            int x=read();
            w_fix(1,l,r,x);
        }
        else if(kind==2){
            int x=read();
            v_fix(1,l,r,x);
        }
        else{
            for(int i=1;i<=m;i++)C[i]=0,f[i]=0;//long long
            query(1,l,r);
            for(int i=1;i<=m;i++){
                for(int j=i;j<=m;j++){
                    f[j]=max(f[j],f[j-i]+C[i]);
                }
            }
            ll ans=0;for(int i=1;i<=m;i++)ans+=f[i];printf("%lld ",ans);//long long
            ans=0;for(int i=1;i<=m;i++)ans^=f[i];printf("%lld\n",ans);
        }
    }
    return 0;
}

【LibreOJ】#6396. 「THUPC2018」弗雷茲的玩具商店 / Toyshop 線段樹+完全背包