描述
给一个长为N的数列,有M次操作,每次操作是以下两种之一:
(1)删除某个位置的数
(2)求数列某位置的值
题解
一开始想的是平衡树,后来想了想没有骚操作,就只要记录该位置是否有效,删除就变成0,然后查询仿值域线段树查k小。
不晓得如果有插入行不行。
#include<bits/stdc++.h> using namespace std; const int maxn=100005; int n,m,cnt; int a[maxn]; int root,ls[maxn<<1],rs[maxn<<1],sum[maxn<<1]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x= f ? -x : x ; } void update(int rt){ sum[rt]=sum[ls[rt]]+sum[rs[rt]]; } void build(int &rt,int l,int r){ rt=++cnt; if(l==r){ sum[rt]=1; return ; } int mid=(l+r)>>1; build(ls[rt],l,mid); build(rs[rt],mid+1,r); update(rt); } void modify(int rt,int l,int r,int pos){ if(l==r){ sum[rt]=0; return; } int mid=(l+r)>>1; if(sum[ls[rt]]>=pos) modify(ls[rt],l,mid,pos); else modify(rs[rt],mid+1,r,pos-sum[ls[rt]]); update(rt); } int query(int rt,int l,int r,int pos){ if(l==r) return a[l]; int mid=(l+r)>>1; if(sum[ls[rt]]>=pos) return query(ls[rt],l,mid,pos); else return query(rs[rt],mid+1,r,pos-sum[ls[rt]]); } int main(){ read(n);read(m); for(int i=1;i<=n;i++) read(a[i]); build(root,1,n); for(int i=1;i<=m;i++){ char op[2]; scanf("%s",op); if(op[0]=='D'){ int pos;read(pos); modify(1,1,n,pos); } else { int pos;read(pos); printf("%d ",query(1,1,n,pos)); } } }