題解 P2596 【[ZJOI2006]書架】
阿新 • • 發佈:2020-08-07
蒟蒻釋出的討論為什麼沒有人理啊!!!!!
題意
讓你寫一種資料結構,可以進行如下操作:
將編號為 \(s\) 的書移動到開頭。
將編號為 \(s\) 的書移動到結尾。
將編號為 \(s\) 的書與其前驅或者後繼交換位置。
詢問編號為 \(s\) 的書前面有幾本書。
詢問位於第 \(s\) 個位置的書的編號。
題解
表示這道題用文藝平衡樹隨便過啊……
但是蒟蒻現在還不會文藝平衡樹,所以怎麼辦?
我們可以考慮給每一個編號附上一個偽權值,然後用平衡樹維護這個偽權值,同時用 \(map\) 記錄偽權值,使得編號和偽權值雙向對映,然後幾種修改操作可以考慮如下實施:
\(top\) 操作就是將原本編號為 \(s\)
程式碼如下:
if(opt=="Top")
{
scanf("%d",&x);
mp2.erase(mp2.find(mp1[x]));
FHQ.erase(mp1[x]);
mp1[x]=--minn;
mp2[minn]=x;
FHQ.insert(minn);
}
\(bottom\) 操作同理,塞入一個最大的偽權值
程式碼如下:
if(opt=="Bottom") { scanf("%d",&x); mp2.erase(mp2.find(mp1[x])); FHQ.erase(mp1[x]); mp1[x]=++maxn; mp2[maxn]=x; FHQ.insert(maxn); }
\(insert\) 操作就是將一個偽權值的前驅(或後繼)與其交換,由於平衡樹是隻記錄偽權值的,所以我們考慮交換進行對映的 \(map\)
程式碼如下:
if(opt=="Insert") { scanf("%d%d",&x,&t); int tmp; if(t==0) continue; if(t==1) tmp=mp2[FHQ.get_nxt(mp1[x])]; else tmp=mp2[FHQ.get_pre(mp1[x])]; swap(mp2[mp1[x]],mp2[mp1[tmp]]); swap(mp1[x],mp1[tmp]); }
但是很顯然,這樣的常數會非常的大,還好本蒟蒻比較臉白,\(AC\) 了。
剩下的比較常規的操作就和完整程式碼一起附上:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
struct fhq_treap
{
int rt;
struct Node
{
int data,rnd;
int son[2];
int size;
}tr[N];
int top,num,rub[N];
int newnode()
{
if(top)
return rub[top--];
return ++num;
}
void up(int p)
{
tr[p].size=tr[tr[p].son[0]].size+tr[tr[p].son[1]].size+1;
return ;
}
void split(int p,int &x,int &y,int val)
{
if(p==0)
{
x=y=0;
return ;
}
if(tr[p].data<val)
x=p,split(tr[p].son[1],tr[p].son[1],y,val);
else
y=p,split(tr[p].son[0],x,tr[p].son[0],val);
up(p);
return ;
}
int merge(int x,int y)
{
if(!x)
return y;
if(!y)
return x;
if(tr[x].rnd<tr[y].rnd)
{
tr[x].son[1]=merge(tr[x].son[1],y);
up(x);
return x;
}
else
{
tr[y].son[0]=merge(x,tr[y].son[0]);
up(y);
return y;
}
}
void insert(int x)
{
int a,b;
split(rt,a,b,x);
int tmp=newnode();
tr[tmp].data=x;
tr[tmp].rnd=rand();
tr[tmp].son[0]=tr[tmp].son[1]=0;
tr[tmp].size=1;
tmp=merge(tmp,b);
rt=merge(a,tmp);
return ;
}
void erase(int x)
{
int a,tmp,b;
split(rt,a,tmp,x);
split(tmp,tmp,b,x+1);
rub[++top]=tmp;
rt=merge(a,b);
return ;
}
int get_rk(int p,int x)
{
if(tr[p].data==x)
return tr[tr[p].son[0]].size+1;
if(tr[p].data>x)
return get_rk(tr[p].son[0],x);
if(tr[p].data<x)
return tr[tr[p].son[0]].size+1+get_rk(tr[p].son[1],x);
}
int get_x(int p,int rk)
{
if(tr[tr[p].son[0]].size+1==rk)
return tr[p].data;
if(tr[tr[p].son[0]].size+1>rk)
return get_x(tr[p].son[0],rk);
if(tr[tr[p].son[0]].size+1<rk)
return get_x(tr[p].son[1],rk-tr[tr[p].son[0]].size-1);
}
int find(int p,int x)
{
if(tr[p].data==x)
return p;
if(tr[p].data>x)
return find(tr[p].son[0],x);
if(tr[p].data<x)
return find(tr[p].son[1],x);
}
int get_pre(int x)
{
return get_x(rt,get_rk(rt,x)-1);
}
int get_nxt(int x)
{
return get_x(rt,get_rk(rt,x)+1);
}
void init()
{
rt=top=num=0;
memset(tr,0,sizeof(tr));
memset(rub,0,sizeof(rub));
}
}FHQ;
int n,m,x,t;
string opt;
unordered_map<int,int> mp1,mp2;
int maxn,minn;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i)
{
scanf("%d",&x);
mp1[x]=i;
mp2[i]=x;
FHQ.insert(i);
}
minn=1,maxn=n;
for(int i=1;i<=m;++i)
{
cin>>opt;
if(opt=="Top")
{
scanf("%d",&x);
mp2.erase(mp2.find(mp1[x]));
FHQ.erase(mp1[x]);
mp1[x]=--minn;
mp2[minn]=x;
FHQ.insert(minn);
}
if(opt=="Bottom")
{
scanf("%d",&x);
mp2.erase(mp2.find(mp1[x]));
FHQ.erase(mp1[x]);
mp1[x]=++maxn;
mp2[maxn]=x;
FHQ.insert(maxn);
}
if(opt=="Insert")
{
scanf("%d%d",&x,&t);
int tmp;
if(t==0)
continue;
if(t==1)
tmp=mp2[FHQ.get_nxt(mp1[x])];
else
tmp=mp2[FHQ.get_pre(mp1[x])];
swap(mp2[mp1[x]],mp2[mp1[tmp]]);
swap(mp1[x],mp1[tmp]);
}
if(opt=="Ask")
scanf("%d",&x),printf("%d\n",FHQ.get_rk(FHQ.rt,mp1[x])-1);
if(opt=="Query")
scanf("%d",&x),printf("%d\n",mp2[FHQ.get_x(FHQ.rt,x)]);
}
}