P3850 [TJOI2007] 书架
P3850 [TJOI2007] 书架
[TJOI2007] 书架
题目描述
Knuth 先生家里有个精致的书架,书架上有
对于
Solution:
最近线段树写吐了捏,来写平衡树捏,平衡树好写捏。
其实我没太搞懂这是怎么评到紫的,我们只需要按照题面维护一颗平衡树,然后对于每个插入操作 (x,k),将 FHQ-Treap 的前 k 个节点splite出来,然后再按照 (L,x,R) 的顺序 merge 回去。
查询也是直接 splite 然后输出,再 merge
感觉没什么难的,几乎没有任何思维难度。
感觉这个甚至比平衡树模板简单
点击此处与妙妙思维平衡题一决高下
Code:
#include<bits/stdc++.h> const int N=1.1e5+5; int rd(){return rand()*rand()+1;} using namespace std; //FHQ-Treap: int n,m,cnt,rt,q; struct FHQ_Treap{ struct Tree{ int ls,rs,val,siz,rnd; }t[N]; void pushup(int x){t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1;} int Node() { cnt++; t[cnt]={0,0,cnt,1,rd()}; return cnt; } void splite(int x,int &a,int &b,int k) { if(!x){a=b=0;return;} int tmp=t[t[x].ls].siz+1; if(tmp<=k) { a=x; splite(t[x].rs,t[a].rs,b,k-tmp); pushup(a); } else { b=x; splite(t[x].ls,a,t[b].ls,k); pushup(b); } } int merge(int x,int y) { if(!x||!y)return x|y; if(t[x].rnd<t[y].rnd) { t[x].rs=merge(t[x].rs,y); pushup(x); return x; } else { t[y].ls=merge(x,t[y].ls); pushup(y); return y; } } }T; string s[N]; void work() { cin>>n; for(int i=1;i<=n;i++) { cin>>s[i]; rt=T.merge(rt,T.Node()); } cin>>m; for(int i=1,k,a,b;i<=m;i++) { cin>>s[T.Node()]; cin>>k; T.splite(rt,a,b,k); rt=T.merge(T.merge(a,cnt),b); } cin>>q; for(int i=1,k,a,b,c;i<=q;i++) { cin>>k; T.splite(rt,a,b,k+1); T.splite(a,a,c,k); cout<<s[T.t[c].val]<<"\n"; rt=T.merge(T.merge(a,c),b); } } int main() { //freopen("P3850.in","r",stdin);freopen("P3850.out","w",stdout); ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); work(); return 0; }