题意:
给你两个栈,多了个合并操作,然后让你模拟
题解:
很容易想到O(1)的单个栈操作,O(n)的合并操作,这样肯定超时,所以我们要将时间复杂度均摊一下,让每个操作都是logn的,于是用上了线段树模拟。
线段树考虑染色,线段树的区间代表的是操作编号,0代表为A栈,1代表为B栈,每次merge 就把1到i这个区间染成指定颜色,然后pop就在线段树中找最右边的对应颜色的点。这样每次操作都是logn
不过官方题解给的是O(n)的解法,反正我是没想到的,感觉智商被压制。
第一份代码是线段树O(nlogn),第二份代码是数组模拟O(n)。也就只能快400ms
Joint Stacks
比较简单巧妙的一个做法是引入一个新的栈C,每次合并的时候就把A和B合并到C上,然后把A和B都清空. push还是按正常做,pop注意当遇到要pop的栈为空时,因为题目保证不会对空栈进行pop操作,所以这时应直接改为对C栈进行pop操作. 这样做因为保证每个元素最多只在一次合并中被处理到,pop和push操作当然也是每个元素只做一次,所以总复杂度是O(N)的. 另一种做法是用链表来直接模拟,复杂度也是O(N),但代码量稍大一些.
1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<<1|1 4 #define mst(a,b) memset(a,b,sizeof(a)) 5 #define F(i,a,b) for(int i=a;i<=b;++i) 6 using namespace std; 7 8 const int N=1e5+7; 9 int n,tr[N<<2],lazy[N<<2],dt[N],now,ic=1; 10 char op[10],x[2],y[2]; 11 12 inline void pd(int rt) 13 { 14 if(lazy[rt]) 15 { 16 if(tr[rt<<1])tr[rt<<1]=lazy[rt],lazy[rt<<1]=lazy[rt]; 17 if(tr[rt<<1|1])tr[rt<<1|1]=lazy[rt],lazy[rt<<1|1]=lazy[rt]; 18 lazy[rt]=0; 19 } 20 } 21 22 void update(int L,int R,int c,int l=1,int r=n,int rt=1) 23 { 24 if(l==r&&L==R){tr[rt]=c;return;} 25 if(L<=l&&r<=R) 26 { 27 if(tr[rt])tr[rt]=c,lazy[rt]=c; 28 return; 29 } 30 pd(rt); 31 int m=(l+r)>>1; 32 if(L<=m)update(L,R,c,ls); 33 if(R>m)update(L,R,c,rs); 34 tr[rt]=tr[rt<<1]|tr[rt<<1|1]; 35 } 36 37 int pop(int x,int l=1,int r=n,int rt=1) 38 { 39 if(l==r){tr[rt]=0;return l;} 40 pd(rt); 41 int ans,m=(l+r)>>1; 42 if(tr[rt<<1|1]&x)ans=pop(x,rs); 43 else ans=pop(x,ls); 44 tr[rt]=tr[rt<<1]|tr[rt<<1|1]; 45 return ans; 46 } 47 int main(){ 48 while(scanf("%d",&n),n) 49 { 50 printf("Case #%d: ",ic++); 51 mst(tr,0),mst(lazy,0); 52 F(i,1,n) 53 { 54 scanf("%s",op); 55 if(op[0]=='p'&&op[1]=='u') 56 { 57 scanf("%s%d",x,dt+i); 58 if(x[0]=='A')update(i,i,1);else update(i,i,2); 59 }else if(op[0]=='p') 60 { 61 scanf("%s",x); 62 if(x[0]=='A')now=pop(1);else now=pop(2); 63 printf("%d ",dt[now]); 64 }else 65 { 66 scanf("%s%s",x,y); 67 if(x[0]=='A')update(1,i,1);else update(1,i,2); 68 } 69 } 70 } 71 return 0; 72 }
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 typedef pair<int,int>P; 5 6 const int N=5e4+7; 7 int eda,edb,edc,n,tp,ic=1,c[N]; 8 char op[10],x[2],y[2]; 9 P a[N],b[N]; 10 11 int main() 12 { 13 while(scanf("%d",&n),n) 14 { 15 printf("Case #%d: ",ic++); 16 eda=edb=edc=0; 17 F(i,1,n) 18 { 19 scanf("%s",op); 20 if(op[0]=='p'&&op[1]=='u') 21 { 22 scanf("%s%d",x,&tp); 23 if(x[0]=='A')a[++eda].first=tp,a[eda].second=i; 24 else b[++edb].first=tp,b[edb].second=i; 25 }else if(op[0]=='p') 26 { 27 scanf("%s",x); 28 if(x[0]=='A') 29 { 30 if(eda)printf("%d ",a[eda--].first); 31 else printf("%d ",c[edc--]); 32 }else 33 { 34 if(edb)printf("%d ",b[edb--].first); 35 else printf("%d ",c[edc--]); 36 } 37 }else 38 { 39 scanf("%s%s",x,y); 40 for(int ii=1,jj=1;ii<=eda||jj<=edb;) 41 { 42 if(ii<=eda&&jj<=edb) 43 { 44 if(a[ii].second<b[jj].second)c[++edc]=a[ii].first,ii++; 45 else c[++edc]=b[jj].first,jj++; 46 }else if(ii<=eda)c[++edc]=a[ii].first,ii++; 47 else if(jj<=edb)c[++edc]=b[jj].first,jj++; 48 } 49 eda=0,edb=0; 50 } 51 } 52 53 } 54 return 0; 55 }