有一個雙端隊列,每一個元素是一個物品,每一個物品有體積和價值兩個屬性。後端
有 \(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; }