题意:给定十万个数a[ m ],然后有十万个操作,每次给现有序列加一个字符(0或1),或者删掉已有序列中,第 a[0] 个,第a[1]个,...,第a[m]个。
序列最多有10万个1或0. 删除操作最多进行10万次。
于是用线段树来储存。每个节点,存这个点还剩下多少个点没有删除,这样就可以删除指定的第k 个数。
给序列加元素最多进行n次,每次复杂度 O(log2(n)) ,最多 O(n*log2(n));
删除元素最多进行 n 次,每次复杂度 O(log2(n)) ,最多 O(n*log2(n));
所以总复杂度O(n*log2(n));
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #define maxn 1000010 using namespace std; int N,n,m,Now,op; int a[maxn]; int index[maxn<<2]; int value[maxn]; void ST_Init(){ N=1;while(N <n+2) N <<=1; memset(index,0,sizeof(index)); } void PushUp(int rt){ index[rt]=index[rt<<1]+index[rt<<1|1]; } void Set(int X,int C,int l,int r,int rt){//将X位置设置为C if(l==r){ value[l]=C; index[rt]=1; ++Now; return; } int m=(l+r)>>1; if(X <=m) Set(X,C,l,m,rt<<1); else Set(X,C,m+1,r,rt<<1|1); PushUp(rt); } void Del(int X,int l,int r,int rt){//删除第X个元素 if(l==r){ index[rt]=0; return; } int m=(l+r)>>1; if(X <= index[rt<<1]) Del(X,l,m,rt<<1); else Del(X-index[rt<<1],m+1,r,rt<<1|1); PushUp(rt); } void show(){//显示 for(int i=0;i<Now;++i){ if(index[N+i]){ printf("%d",value[i+1]); } } cout<<endl; } int main(void) { while(~scanf("%d%d",&n,&m)){ Now=1;ST_Init(); for(int i=0;i<m;++i) scanf("%d",&a[i]); for(int i=0;i<n;++i) { scanf("%d",&op); if(~op){ Set(Now,op,1,N,1); } else{ for(int j=0;j<m&&a[j]-j<=index[1];j++){//<span style="font-family: Arial, Helvetica, sans-serif;">注意,这里是删掉第a[ j ]</span><span style="font-family: Arial, Helvetica, sans-serif;">个元素,</span> Del(a[j]-j,1,N,1);//因为已经删掉了j个元素了,本次操作前的第a[j]个是现在的第 <span style="font-family: Arial, Helvetica, sans-serif;">a[ j ] - j 个</span><span style="font-family: Arial, Helvetica, sans-serif;">。</span> } } } if(index[1]){ show(); } else{ printf("Poor stack!\n"); } } return 0; }