题目大意:给定一串数字,有两种操作,第一种是在最后面插入一个元素,第二种是查询第i个元素,如果有就输出并删除;
题目解析:线段树先构造出n+m,每个区间我们需要维护有多少个数字,如果当前查询的是pos,左二子的数字>=pos,那么就查询左二子,否则pos-=num[rt<<1],再查询右儿子。
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn=150010;
int num[maxn*4],val[maxn*4],ans;
void pushup(int rt)
{
num[rt]=num[rt<<1]+num[rt<<1|1];
}
void build(int l,int r,int rt)
{
num[rt]=0;
val[rt]=-1;
if(l==r) return ;
int m=(l+r)>>1;
build(lson);
build(rson);
}
void update(int pos,int v,int l,int r,int rt)
{
if(pos==l&&pos==r)
{
num[rt]=1;
val[rt]=v;
return ;
}
int m=(l+r)>>1;
if(m>=pos) update(pos,v,lson);
else if(m<pos) update(pos,v,rson);
pushup(rt);
}
void query(int pos,int l,int r,int rt)
{
num[rt]--;
if(l==r)
{
ans=val[rt];
val[rt]=-1;
return ;
}
int m=(l+r)>>1;
if(num[rt<<1]>=pos)
{
query(pos,lson);
}
else
{
pos-=num[rt<<1];
query(pos,rson);
}
}
int main()
{
int cas,c,n,m,i,x,t;
scanf("%d",&cas);
for(c=1;c<=cas;c++)
{
scanf("%d%d",&n,&m);
int nn=n+m;
build(1,nn,1);
printf("Case %d:\n",c);
for(i=1;i<=n;i++)
{
scanf("%d",&t);
update(i,t,1,nn,1);
}
while(m--)
{
char s[2];
scanf("%s%d",&s[0],&x);
if(s[0]=='c')
{
query(x,1,nn,1);
if(ans==-1) printf("none\n");
else printf("%d\n",ans);
}
else
{
n+=1;
update(n,x,1,nn,1);
}
}
}
return 0;
}