有一个双端队列,每一个元素是一个物品,每一个物品有体积和价值两个属性。后端
有 \(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; }