Solution
离线做法很简单,就是线段树分治,不过复杂度是
q
m
o
d
log
qmod\log
qmodlog。
考虑在线做法,在线段树分治中,我们并没有利用到删除以及加入都只会在两端进行这个性质,我们考虑用两个栈分别维护两端,每次加入一个数就暴力做背包,删除就删除栈顶。当某一个栈被删空了之后,就把现有的数均等分成两份,扔进两个栈中暴力重构。
询问的话,一开始也想过分成两段维护,但一直没有办法快速合并两段的状态,其实并不需要合并起来,枚举第一个栈中贡献的余数,那么就相当于询问另一栈中的区间最大值,可以发现每次询问的区间都是长度相等的一段,所以可以用单调队列维护最大值。
复杂度是
q
m
o
d
qmod
qmod。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=50010;
const LL inf=4485090715960753727LL;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int m,mod,w[Maxn<<1],v[Maxn<<1];
LL s1[Maxn][505],s2[Maxn][505];
int t1=0,t2=0,l=50001,r=50000,mid=50000;
char op[5];
void clear1(int x){memset(s1[x],-63,sizeof(s1[x]));}
void clear2(int x){memset(s2[x],-63,sizeof(s2[x]));}
void add1(int x)
{
t1++;clear1(t1);
memcpy(s1[t1],s1[t1-1],sizeof(s1[t1]));
for(int i=0;i<mod;i++)
{
int j=(i+w[x])%mod;
s1[t1][j]=max(s1[t1][j],s1[t1-1][i]+v[x]);
}
}
void add2(int x)
{
t2++;clear2(t2);
memcpy(s2[t2],s2[t2-1],sizeof(s2[t2]));
for(int i=0;i<mod;i++)
{
int j=(i+w[x])%mod;
s2[t2][j]=max(s2[t2][j],s2[t2-1][i]+v[x]);
}
}
vector<int>h[1005];
int tot,to[505];LL Ans[505],a[1005];
int q[505];
LL query(int L,int R)
{
LL re=-inf;tot=0;int len=R-L+1;
for(int i=0;i<mod+mod;i++)h[i].clear();
for(int i=0;i<mod;i++)
{
int ll=L-i,rr=R-i;
if(ll<0)ll+=mod;if(rr<0)rr+=mod;
if(ll>rr)rr+=mod;
h[rr].push_back(to[i]=++tot);
}
int head=1,tail=0;
for(int i=0;i<mod+mod;i++)
{
LL x=s2[t2][i%mod];a[i]=x;
while(head<=tail&&i-q[head]+1>len)head++;
while(head<=tail&&x>=a[q[tail]])tail--;
q[++tail]=i;
for(int j=0;j<h[i].size();j++)Ans[h[i][j]]=a[q[head]];
}
for(int i=0;i<mod;i++)
if(s1[t1][i]>=0&&Ans[to[i]]>=0)re=max(re,s1[t1][i]+Ans[to[i]]);
if(re<=-inf)return -1;
return re;
}
void rebuild()
{
mid=l+r>>1;
t1=t2=0;clear1(0);clear2(0);s1[0][0]=s2[0][0]=0;
for(int i=mid;i>=l;i--)add1(i);
for(int i=mid+1;i<=r;i++)add2(i);
}
int main()
{
read();
m=read(),mod=read();
clear1(0),clear2(0);
s1[0][0]=s2[0][0]=0;
while(m--)
{
scanf("%s",op);
if(op[0]=='I')
{
if(op[1]=='F')l--,w[l]=read()%mod,v[l]=read(),add1(l);
else r++,w[r]=read()%mod,v[r]=read(),add2(r);
}
else if(op[0]=='Q')
{
int L=read(),R=read();
printf("%lld\n",query(L,R));
}
else
{
if(op[1]=='F')
{
l++,t1--;
if(l>mid)rebuild();
}
else
{
r--,t2--;
if(r<=mid)rebuild();
}
}
}
}