[ZJOI2006]书架(二分+树状数组)

这题90%以上的人做法为裸的平衡树,实际上根本没必要还常数大,最好的方法是二分+树状数组。具体做法是,开3倍内存,初始把中间n位赋值为1。对于每个操作:1&2、删除该位,将其丢在头/尾(开三倍内存的原因)。3、插入时直接二分查询第ask(x)+y位,换一下即可。4、直接查询。5、二分查询。复杂度O(nlog2n)

#include<bits/stdc++.h>
using namespace std;
const int N=240010;
int n,m,a[N],id[N],c[N];
void add(int x,int v){while(x<=2*m+n)c[x]+=v,x+=x&-x;}
int ask(int x){int ret=0;while(x)ret+=c[x],x-=x&-x;return ret;}
int find(int x)
{
    int l=1,r=2*m+n,mid,pos=2*m+n;
    while(l<=r)
    {
        mid=l+r>>1;
        if(ask(mid)>=x)pos=mid,r=mid-1;
        else l=mid+1;
    }
    return pos;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x;i<=n;i++)scanf("%d",&a[i+m]),id[a[i+m]]=i+m,add(i+m,1);
    for(int i=1;i<=m;i++)
    {
        char str[10];int x,y,t,pos,tmp;
        scanf("%s%d",str,&x);
        if(str[0]=='T')pos=find(1),add(id[x],-1),add(pos-1,1),id[x]=pos-1,a[id[x]]=x;
        if(str[0]=='B')pos=find(n),add(id[x],-1),add(pos+1,1),id[x]=pos+1,a[id[x]]=x;
        if(str[0]=='I')
        {
            scanf("%d",&y);
            if(!y)continue;
            pos=find(ask(id[x])+y),tmp=a[pos];
            swap(a[pos],a[id[x]]),swap(id[x],id[tmp]);
        }
        if(str[0]=='A')printf("%d\n",ask(id[x])-1);
        if(str[0]=='Q')printf("%d\n",a[find(x)]);
    }
}
View Code

 

posted @ 2019-05-23 13:20  hfctf0210  阅读(200)  评论(0编辑  收藏  举报