FHQ treap
之前就差不多会了,但是一直没时间写。
原理还是挺好理解的,都是基于split和merge两个操作。
如果是维护集合的话,那么平衡树原来维护的就是权值,按权值分裂。
如果是维护序列的话,原来平衡树维护的权值就相当于下标,按排名分裂,那么中序遍历就是我们的原序列。
注意要srand
P3369 【模板】普通平衡树
#include<cstdio>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=2e5+5;
int v[N],ls[N],rs[N],s[N],p[N];
int cnt,rt,op,x,l,r,z;
void newnode(int x){
++cnt;
v[cnt]=x;
ls[cnt]=rs[cnt]=0;
s[cnt]=1;
p[cnt]=rand();
}
void update(int x){
s[x]=s[ls[x]]+s[rs[x]]+1;
}
void split(int u,int x,int &l,int &r){
if (!u) {
l=r=0; return;
}
if (v[u]<=x){
l=u;
split(rs[u],x,rs[u],r);
}
else{
r=u;
split(ls[u],x,l,ls[u]);
}
update(u);
}
int merge(int l,int r){
if (!l || !r) return l+r;
if (p[l]>p[r]){
rs[l]=merge(rs[l],r);
update(l);
return l;
}
else{
ls[r]=merge(l,ls[r]);
update(r);
return r;
}
}
void ins(int x){
newnode(x);
split(rt,x,l,r);
rt=merge(l,cnt);
rt=merge(rt,r);
}
void del(int x){
split(rt,x-1,l,r);
split(r,x,z,r);
z=merge(ls[z],rs[z]);
rt=merge(l,z);
rt=merge(rt,r);
}
void Rank(int x){
split(rt,x-1,l,r);
printf("%d\n",s[l]+1);
rt=merge(l,r);
}
void kth(int u,int x){
if (s[ls[u]]+1==x) {
printf("%d\n",v[u]);
return;
}
if (s[ls[u]]+1<x) kth(rs[u],x-s[ls[u]]-1);
else kth(ls[u],x);
}
void pre(int x){
split(rt,x-1,l,r);
kth(l,s[l]);
rt=merge(l,r);
}
void suf(int x){
split(rt,x,l,r);
kth(r,1);
rt=merge(l,r);
}
int main(){
// freopen("data.in","r",stdin);
srand(time(NULL));
int T;
scanf("%d",&T);
while (T--){
scanf("%d %d",&op,&x);
switch (op) {
case 1: ins(x); break;
case 2: del(x); break;
case 3: Rank(x); break;
case 4: kth(rt,x); break;
case 5: pre(x); break;
case 6: suf(x); break;
}
}
return 0;
}
基本操作是一样的,用tag标记是否翻转,然后在merge和split的时候注意下传即可。
#include<cstdio>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=1e5+5;
int v[N],ls[N],rs[N],s[N],cnt,p[N];
int n,m,rt,x,y,l,r,z;
bool t[N];
void update(int x){
s[x]=s[ls[x]]+s[rs[x]]+1;
}
void newnode(int x){
++cnt;
v[cnt]=x;
ls[cnt]=rs[cnt]=0;
p[cnt]=rand();
s[cnt]=1;
}
void push(int x){
if (t[x]) {
swap(ls[x],rs[x]);
t[ls[x]]^=1;
t[rs[x]]^=1;
t[x]=0;
}
}
void split(int u,int x,int &l,int &r){
if (!u) {
l=r=0; return;
}
push(u);
if (s[ls[u]]+1<=x) {
l=u;
split(rs[u], x-1-s[ls[u]], rs[u], r);
}
else{
r=u;
split(ls[u], x, l, ls[u]);
}
update(u);
}
int merge(int l,int r){
if (!l || !r) return l+r;
push(l); push(r);
if (p[l]>=p[r]) {
rs[l]=merge(rs[l],r);
update(l);
return l;
}
else{
ls[r]=merge(l,ls[r]);
update(r);
return r;
}
}
void pf(int x){
if (!x) return;
push(x);
pf(ls[x]);
printf("%d ",v[x]);
pf(rs[x]);
}
int main(){
srand(time(NULL));
// freopen("data.in","r",stdin);
scanf("%d %d",&n,&m);
fo(i,1,n) {
newnode(i);
rt=merge(rt,cnt);
}
while (m--){
scanf("%d %d",&x,&y);
split(rt,y,l,r);
split(l,x-1,l,z);
t[z]^=1;
rt=merge(l,z);
rt=merge(rt,r);
}
pf(rt);
return 0;
}
#include<cstdio>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long ll;
const int N=1e6+5;
int p[N],v[N],ls[N],rs[N],s[N],cnt,rt;
ll t[N],e[N];
int n,m,x,y,op,z,l,r;
ll k;
void update(int x){
s[x]=s[ls[x]]+s[rs[x]]+1;
e[x]=(v[x]+e[ls[x]]+e[rs[x]]);
}
void New(int x){
++cnt;
p[cnt]=rand();
ls[cnt]=rs[cnt]=0;
s[cnt]=1;
e[cnt]=v[cnt]=x;
}
void push(int x){
if (t[x]) {
e[ls[x]]+=(ll)s[ls[x]]*t[x];
v[ls[x]]+=t[x];
t[ls[x]]+=t[x];
e[rs[x]]+=(ll)s[rs[x]]*t[x];
v[rs[x]]+=t[x];
t[rs[x]]+=t[x];
t[x]=0;
}
}
void split(int u,int x,int &l,int &r){
if (!u) {
l=r=0; return;
}
push(u);
if (s[ls[u]]+1<=x) {
l=u;
split(rs[u], x-s[ls[u]]-1, rs[u], r);
}
else{
r=u;
split(ls[u], x, l, ls[u]);
}
update(u);
}
int merge(int l,int r){
if (!l || !r) return l+r;
push(l); push(r);
if (p[l]>=p[r]){
rs[l]=merge(rs[l],r);
update(l);
return l;
}
else{
ls[r]=merge(l,ls[r]);
update(r);
return r;
}
}
int main(){
srand(time(NULL));
// freopen("data.in","r",stdin);
scanf("%d %d",&n,&m);
fo(i,1,n) {
scanf("%d",&x);
New(x);
rt=merge(rt,cnt);
}
while (m--){
scanf("%d %d %d",&op, &x, &y);
if (op==1) {
scanf("%lld",&k);
split(rt,y,l,r);
split(l,x-1,l,z);
t[z]+=k;
v[z]+=k;
e[z]+=k*s[z];
rt=merge(l,z);
rt=merge(rt,r);
}
else{
split(rt,y,l,r);
split(l,x-1,l,z);
printf("%lld\n",e[z]);
rt=merge(l,z);
rt=merge(rt,r);
}
}
return 0;
}
P1486 [NOI2004] 郁闷的出纳员
经典板题
按权值分类之后,比min小的直接丢掉即可。
#include<cstdio>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=3e5+5;
int mn,cnt,rt,l,r,x;
int p[N],ls[N],rs[N],s[N],t[N],tot,v[N];
char ch;
void New(int x){
++cnt;
p[cnt]=rand();
ls[cnt]=rs[cnt]=0;
s[cnt]=1;
t[cnt]=0;
v[cnt]=x;
}
void upd(int x){
s[x]=s[ls[x]]+s[rs[x]]+1;
}
void push(int x){
if (t[x]) {
t[ls[x]]+=t[x];
v[ls[x]]+=t[x];
t[rs[x]]+=t[x];
v[rs[x]]+=t[x];
t[x]=0;
}
}
void split(int u,int x,int &l,int &r){
if (!u) {
l=r=0; return;
}
push(u);
if (v[u]<=x){
l=u;
split(rs[u],x,rs[u],r);
}
else{
r=u;
split(ls[u],x,l,ls[u]);
}
upd(u);
}
int merge(int l,int r){
if (!l || !r) return l+r;
if (p[l]>=p[r]) {
rs[l]=merge(rs[l],r);
upd(l);
return l;
}
else{
ls[r]=merge(l,ls[r]);
upd(r);
return r;
}
}
void ins(int x){
New(x);
split(rt,x,l,r);
rt=merge(l,cnt);
rt=merge(rt,r);
}
void kth(int u,int x){
if (s[ls[u]]+1==x) {
printf("%d\n",v[u]);
return;
}
push(u);
if (s[ls[u]]+1<x) kth(rs[u],x-s[ls[u]]-1);
else kth(ls[u],x);
}
int main(){
srand(time(NULL));
// freopen("data.in","r",stdin);
int T;
scanf("%d %d\n",&T,&mn);
while (T--) {
scanf("%c %d\n",&ch,&x);
switch (ch) {
case 'I':
if (x>=mn) {
ins(x);
tot++;
}
break;
case 'A':
t[rt]+=x;
v[rt]+=x;
break;
case 'S':
t[rt]-=x;
v[rt]-=x;
split(rt,mn-1,l,r);
rt=r;
break;
case 'F':
if (s[rt]<x) puts("-1");
else{
kth(rt,s[rt]-x+1);
}
break;
}
}
printf("%d",tot-s[rt]);
return 0;
}
P2596 [ZJOI2006]书架
我们在这里要维护的是区间,原来的FHQ treap并不支持通过编号查找排名,所以我们需要维护每个点的父亲,然后算出它的排名。
#include<cstdio>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=1e5+5;
int p[N],ls[N],rs[N],s[N],v[N],id[N]; // pos of xth book
int f[N];
int n,m,rt,cnt,x,l,r,y,z,a,b,k;
char ch[10];
void New(int x){
++cnt;
p[cnt]=rand();
ls[cnt]=rs[cnt]=0;
s[cnt]=1;
v[cnt]=x;
}
void upd(int x){
s[x]=s[ls[x]]+s[rs[x]]+1;
if (ls[x]) f[ls[x]]=x;
if (rs[x]) f[rs[x]]=x;
}
void split(int u,int x,int &l,int &r){
if (!u) {
l=r=0; return;
}
if (s[ls[u]]+1<=x) {
l=u;
split(rs[u], x-s[ls[u]]-1, rs[u], r);
}
else{
r=u;
split(ls[u], x, l, ls[u]);
}
upd(u);
}
int merge(int l,int r){
if (!l || !r) return l+r;
if (p[l]>p[r]) {
rs[l]=merge(rs[l],r);
upd(l);
return l;
}
else{
ls[r]=merge(l,ls[r]);
upd(r);
return r;
}
}
int get(int x){
if (x==rt) return 1;
if (x==rs[f[x]]) {
return get(f[x])+1+s[ls[f[x]]];
}
else{
return get(f[x]);
}
}
void kth(int u,int x){
if (!x) return;
if (s[ls[u]]+1==x) {
printf("%d\n",v[u]);
return;
}
if (s[ls[u]]+1<x) kth(rs[u],x-s[ls[u]]-1);
else kth(ls[u],x);
}
void pf(int x){
if (!x) return;
pf(ls[x]);
printf("%d ",v[x]);
pf(rs[x]);
}
void ask(int x){
k=0;
k=get(id[x])+s[ls[id[x]]];
}
int main(){
srand(time(NULL));
// freopen("data.in","r",stdin);
scanf("%d %d",&n,&m);
fo(i,1,n) {
scanf("%d",&x);
New(x);
id[x]=cnt;
rt=merge(rt,cnt);
}
while (m--) {
scanf("%s %d\n",ch,&x);
switch (ch[0]) {
case 'T':
ask(x);
split(rt,k,l,r);
split(l,k-1,l,z);
rt=merge(z,l);
rt=merge(rt,r);
break;
case 'B':
ask(x);
split(rt,k,l,r);
split(l,k-1,l,z);
rt=merge(l,r);
rt=merge(rt,z);
break;
case 'I':
scanf("%d",&y);
if (y==1) {
ask(x);
split(rt,k+1,l,r);
split(l,k,l,b);
split(l,k-1,l,a);
rt=merge(l,b);
rt=merge(rt,a);
rt=merge(rt,r);
}
if (y==-1){
ask(x);
split(rt,k,l,r);
split(l,k-1,l,a);
split(l,k-2,l,b);
rt=merge(l,a);
rt=merge(rt,b);
rt=merge(rt,r);
}
break;
case 'A':
ask(x);
printf("%d\n",k-1);
break;
case 'Q' :
kth(rt,x);
break;
}
}
return 0;
}