XUANMING'S JOURNAL屏幕在深夜微微发亮,我心在远方。
← 回到笔记
FIELD NOTES

luoguP3850题解

题外话:这个题不是裸题吗

看好题解比较少我就进来了

$FHQ\_treap$维护区间

能维护区间的平衡树比较少,本蒟蒻只会$splay$与$fhq$

我也只会这两种平衡树

平衡树维护区间与一般的平衡树的定义有点不同,一棵维护区间的平衡树满足:

它的任意一个节点任何一个左儿子的下标比它小,右儿子比它大。

节点维护size,在split时按size分。

#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#include <ctime>
using namespace std;
const int maxn=1e5+205;

struct FHQ_Node
{
	int ch[2],siz,rnd;
	string val;
}tr[maxn];
int utot;

inline int newnode(string val) {tr[++utot].rnd=rand();tr[utot].siz=1;tr[utot].val=val;return utot;}

inline void update(int u) {tr[u].siz=tr[tr[u].ch[0]].siz+tr[tr[u].ch[1]].siz+1;}

inline void split(int u,int siz,int &x,int &y)
{
	if(!u) return void(x=y=0);
	if(tr[tr[u].ch[0]].siz>=siz) y=u,split(tr[u].ch[0],siz,x,tr[u].ch[0]);//左儿子的size+1表示它在区间中的排名
	else x=u,split(tr[u].ch[1],siz-tr[tr[u].ch[0]].siz-1,tr[u].ch[1],y);
	update(u);
}

inline int merge(int x,int y)
{
	if(!x||!y) return x|y;
	if(tr[x].rnd<tr[y].rnd)
	{
		tr[x].ch[1]=merge(tr[x].ch[1],y);update(x);return x;
	}
	else
	{
		tr[y].ch[0]=merge(x,tr[y].ch[0]);update(y);return y;
	}
}

int main()
{
	ios::sync_with_stdio(false);
	srand(time(0));
	int n,rt=0,r1=0,r2=0,x,m,q;
	string s;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		rt=merge(rt,newnode(s));
	}
	cin>>m;
	while(m--)
	{
		cin>>s>>x;
		split(rt,x,rt,r1);
		rt=merge(rt,merge(newnode(s),r1));
	}
	cin>>q;
	while(q--)
	{
		cin>>x;
		split(rt,x+1,rt,r1);
		split(rt,x,rt,r2);
		cout<<tr[r2].val<<endl;
		rt=merge(rt,merge(r2,r1));
	}
	return 0;
}

另外,听说$splay$在维护区间的时候比$fhq$要快但主要是因为$fhq$好打

输入关键词,搜索全部笔记。