NOI 十连测 Zbox loves stack
题目描述 (4s,1G)
从小热爱计算机的Zbox开始玩栈了.Zbox有n个栈,他命令你支持如下操作:
*.把第l个栈到第r个栈都压入一个元素x
*.把第l个栈到第r个栈都弹出栈顶(若栈为空则无视)
*.询问第s个栈的第k个元素是多少(栈顶为第一个元素)
输入描述
第一行2个数n,q
接下来q行,每行第一个数为t
若t为0,输入l,r,x,把第l个栈到第r个栈都压入一个元素x
若t为1,输入l,r,把第l个栈到第r个栈都弹出栈顶
若t为2,输入s,k,询问第s个栈的第k个元素是多少,若栈中没有k个元素则输出"Error"
输出描述
对于每一个t=2的操作,输出一行"Error"或一个数表示答案
数据规模
对于10%的数据,n<=5000,q<=5000
对于30%的数据,n<=100000,q<=30000
对于另外10%的数据,保证没有t=1的操作
对于另外10%的数据,所有t=0的操作满足l=r
对于另外10%的数据,所有t=1的操作满足l=r
对于另外10%的数据,所有t=2的操作满足k=1
对于另外10%的数据,保证不会输出"Error"
对于100%的数据,n<=1000000,q<=100000,所有输入的数在[0,2^31-1]之间
SOL: 我们可以信仰暴力N方过百万,然后这题目就过了
这题 的标算 也 是O(N log ^2)的。
我们考虑线段树维护区间,那么我们需要一种数据结构来维护查询K大元素,快速数据下传。 我们发现 fhq treap可以胜任。我们同时要求前后数据的修改无关,那么我们可以可持久化这玩意。
#pragma GCC optimize("-O3") #include<bits/stdc++.h> #define rr NULL #define N 1000005 using namespace std; #define sight(x) ('0'<=x&&x<='9') inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);} inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); } inline void writel(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } inline int rop(){ static int x=23333; return x^=x<<13,x^=x>>17,x^=x<<5; } int lazy[N<<2]; struct T{ int key,val,siz; T* son[2]; T() {} T(int x){siz=1;key=x;val=rop();son[0]=son[1]=rr;} void be() { siz=1; if (son[0]) siz+=son[0]->siz; if (son[1]) siz+=son[1]->siz; } inline int ibt() {return son[0]?son[0]->siz+1:1;} inline int Siz() {return this!=0?siz:0;} }; T *root[N<<2]; struct Tre{ void split(T* now,int k,T* &x,T* &y) { if (!now) {x=y=rr; return;} int cmp=now->ibt(); if (k<cmp) y=new T(),*y=*now,split(y->son[0],k,x,y->son[0]),y->be(); else x=new T(),*x=*now,split(x->son[1],k-cmp,x->son[1],y),x->be(); } T* merge(T* x,T* y) { if (!x) return y; if (!y) return x; T *X=new T(); if (x->val<y->val){ *X=*x; X->son[1]=merge(X->son[1],y); } else { *X=*y; X->son[0]=merge(x,X->son[0]); } X->be(); return X; } int t; T* xt,*yt,*zt; inline void del(int rot,int x) { t=min(x,root[rot]->Siz()); split(root[rot],root[rot]->Siz()-t,xt,yt); root[rot]=xt; lazy[rot]+=(x-t); } inline void ins(int rot,int x) { root[rot]=merge(root[rot],new T(x)); } void que(int k,int x){ zt=root[k]; if (zt->Siz()<x) {printf("Error\n"); return;} t=zt->siz-x+1; split(zt,t,xt,yt); split(xt,t-1,xt,yt); writeln(yt->key); } }treap; #define Mid (l+r>>1) struct Segment{ inline void pd(int k,bool op){ if (op) {lazy[k]=0; return;} if (lazy[k]>0) { treap.del(k<<1,lazy[k]); treap.del(k<<1|1,lazy[k]); lazy[k]=0; } root[k<<1]=treap.merge(root[k<<1],root[k]); root[k<<1|1]=treap.merge(root[k<<1|1],root[k]); root[k]=rr; } void ins(int k,int l,int r,int L,int R,int id){ pd(k,l==r); if (L<=l&&r<=R) {treap.ins(k,id); return;} if (L<=Mid) ins(k<<1,l,Mid,L,R,id); if (R> Mid) ins(k<<1|1,Mid+1,r,L,R,id); } void del(int k,int l,int r,int L,int R){ pd(k,l==r); if (L<=l&&r<=R) {treap.del(k,1); return;} if (L<=Mid) del(k<<1,l,Mid,L,R); if (R> Mid) del(k<<1|1,Mid+1,r,L,R); } void que(int k,int l,int r,int x,int id){ pd(k,l==r); if (l==r) {treap.que(k,id); return;} if (x<=Mid) que(k<<1,l,Mid,x,id); else que(k<<1|1,Mid+1,r,x,id); } }Tree; int n,q,op,l,r,w; signed main () { freopen("stack.in","r",stdin); freopen("stack.out","w",stdout); read(n); read(q); while (q--) { read(op); read(l); read(r); if (op==0) read(w),Tree.ins(1,1,n,l,r,w); else if (op==1) Tree.del(1,1,n,l,r); else Tree.que(1,1,n,l,r); // cerr<<tot<<endl; } return 0; }