【LOJ6515】貪玩藍月

題目大意

  有一個雙端隊列,每一個元素是一個物品,每一個物品有體積和價值兩個屬性。後端

  有 \(n\) 個操做,分爲 \(5\) 種:先後端插入刪除,還有詢問:選出一些物品,知足這些物品的體積之和模 \(p\)\([l,r]\) 之間,問你價值和最大是多少。dom

  \(n\leq 50000,p\leq 500\)ui

題解

離線作法

  處理出每一個物品加入隊列的時間和刪除的時間,插入到線段樹裏面分治就行了。spa

  時間複雜度:\(O(np\log n)\)code

在線作法

  考慮對於一個隊列,從中間向兩邊各建一個可持久化棧維護兩邊中間到兩邊的物品加在一塊兒的信息。隊列

  若是刪除後把某一個棧的棧底刪掉了,就從中間開始重構這兩個棧。get

  對於一個詢問,枚舉左邊的物品體積是多少,而後右邊的物品體積就是一個區間。string

  能夠按照 \(r-l+1\) 分塊,這樣每次詢問就是塊內的一個前綴和一個後綴。it

  時間複雜度:\(O(np)\)io

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<functional>
#include<cmath>
#include<vector>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
    char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
void open2(const char *s){
#ifdef DEBUG
    char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const int N=50010;
const int P=510;
const ll inf=0x3fffffffffffffffll;
struct info
{
    ll a[P];
    ll &operator [](int x)
    {
        return a[x];
    }
    void clear()
    {
        memset(a,0xc0,sizeof a);
        a[0]=0;
    }
};
int n,p;
info a1[N],a2[N];
int l,r,mid;
int t1,t2;
int w[2*N],v[2*N];
void init()
{
    l=50001;
    r=50000;
    mid=50000;
    a1[0].clear();
    a2[0].clear();
}
void addl(int x)
{
    t1++;
    a1[t1]=a1[t1-1];
    for(int i=0;i<p;i++)
        a1[t1][(i+w[x])%p]=max(a1[t1][(i+w[x])%p],a1[t1-1][i]+v[x]);
}
void addr(int x)
{
    t2++;
    a2[t2]=a2[t2-1];
    for(int i=0;i<p;i++)
        a2[t2][(i+w[x])%p]=max(a2[t2][(i+w[x])%p],a2[t2-1][i]+v[x]);
}
void rebuild()
{
    mid=(l+r)>>1;
    t1=0;
    t2=0;
    for(int i=mid;i>=l;i--)
        addl(i);
    for(int i=mid+1;i<=r;i++)
        addr(i);
}
int pre[P],suf[P];
void query()
{
    int ql,qr;
    scanf("%d%d",&ql,&qr);
    int len=qr-ql+1;
    ll s=-inf;
    for(int i=0;i<p;i++)
    {
        if(i%len==0)
            s=-inf;
        s=max(s,a1[t1][i]);
        pre[i]=s;
    }
    s=-inf;
    for(int i=p-1;i>=0;i--)
    {
        if(i%len==len-1)
            s=-inf;
        s=max(s,a1[t1][i]);
        suf[i]=s;
    }
    ll ans=-1;
//  for(int i=0;i<p;i++)
//      for(int j=0;j<p;j++)
//          if((i+j)%p>=ql&&(i+j)%p<=qr)
//          {
//              ans=max(ans,a1[t1][i]+a2[t2][j]);
//              if(ans==481594)
//                  int xxx=1;
//          }
    for(int i=0;i<p;i++)
    {
        int _l=ql-i;
        int _r=qr-i;
        if(_l<0)
            _l+=p;
        if(_r<0)
            _r+=p;
        ans=max(ans,a2[t2][i]+max(pre[_r],suf[_l]));
        int z=p/len*len;
        if(_l>_r&&_l<z)
            ans=max(ans,a2[t2][i]+suf[z]);
    }
    printf("%lld\n",ans);
}
char op[10];
void gao()
{
    scanf("%s",op);
    if(op[0]=='I')
    {
        if(op[1]=='F')
        {
            l--;
            scanf("%d%d",&w[l],&v[l]);
            w[l]%=p;
            addl(l);
        }
        else
        {
            r++;
            scanf("%d%d",&w[r],&v[r]);
            w[r]%=p;
            addr(r);
        }
    }
    else if(op[0]=='D')
    {
        if(op[1]=='F')
        {
            l++;
            t1--;
            if(l>mid+1)
                rebuild();
        }
        else
        {
            r--;
            t2--;
            if(r<=mid+1)
                rebuild();
        }
    }
    else
    {
        query();
    }
}
int main()
{
    open("loj6515");
    rd();
    scanf("%d%d",&n,&p);
    init();
    for(int i=1;i<=n;i++)
    {
        if(i==75)
            int xxx=1;
        gao();
//      if(op[0]=='Q')
//          printf("%d\n",i);
    }
    return 0;
}
相關文章
相關標籤/搜索