各位大佬讲得真好 我既然讲不好就不讲了
http://www.cnblogs.com/mjtcn/p/8028926.html
https://blog.csdn.net/cabi_zgx/article/details/79963427
https://www.luogu.org/blog/Chanis/fhq-treap
https://www.cnblogs.com/BCOI/p/9072444.html
非旋treap常数大
【模板】普通平衡树
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入x数
- 删除x数(若有多个相同的数,因只删除一个)
- 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
输入输出格式
输入格式:
第一行为n,表示操作的个数,下面nn行每行有两个数opt和x,opt表示操作的序号(1≤opt≤6 )
输出格式:
对于操作3,4,5,6每行输出一个数,表示对应答案
输入输出样例
输入样例#1:
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
输出样例#1:
106465
84185
492737
说明
时空限制:1000ms,128M
1.n的数据范围: n≤100000
2.每个数的数据范围: [-10^7, 10^7]
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5*100000+5;
int num,root,ch[N][2],val[N],rnd[N],siz[N];
inline void pushup(int x)
{siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;}
inline int make(int x)
{val[++num]=x; rnd[num]=rand(); siz[num]=1;
return num;
}
void split(int now,int k,int &x,int &y)
{if(!now) x=y=0;
else
{if(val[now]<=k)
{x=now; split(ch[now][1],k,ch[now][1],y);
}
else
{y=now; split(ch[now][0],k,x,ch[now][0]);
}
pushup(now);
}
}
int merge(int x,int y)
{if(!x || !y) return x+y;
if(rnd[x]<=rnd[y])
{ch[x][1]=merge(ch[x][1],y);
pushup(x); return x;
}
else
{ch[y][0]=merge(x,ch[y][0]);
pushup(y); return y;
}
}
inline int getkth(int p,int k)
{while(1)
{if(k==siz[ch[p][0]]+1) return p;
if(ch[p][0] && k<=siz[ch[p][0]]) p=ch[p][0];
else {k=k-siz[ch[p][0]]-1;
p=ch[p][1];
}
}
}
int main()
{int m,op,k,x,y,z; scanf("%d",&m);
while(m--)
{scanf("%d%d",&op,&k);
if(op==1)
{split(root,k,x,y);
root=merge(merge(x,make(k)),y);
}
else if(op==2)
{split(root,k,x,y);
split(x,k-1,x,z);
z=merge(ch[z][0],ch[z][1]);
root=merge(merge(x,z),y);
}
else if(op==3)
{split(root,k-1,x,y);
printf("%d\n",siz[x]+1);
root=merge(x,y);
}
else if(op==4)
{printf("%d\n",val[getkth(root,k)]);
}
else if(op==5)
{split(root,k-1,x,y);
printf("%d\n",val[getkth(x,siz[x])]);
root=merge(x,y);
}
else if(op==6)
{split(root,k,x,y);
printf("%d\n",val[getkth(y,1)]);
root=merge(x,y);
}
}
return 0;
}
BZOJ1251: 序列终结者
Description
网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列 要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。这道题目 就叫序列终结者吧。 【问题描述】 给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作: 1. 将[L,R]这个区间内的所有数加上V。 2. 将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。 3. 求[L,R]这个区间中的最大值。 最开始所有元素都是0。
Input
第一行两个整数N,M。M为操作个数。 以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。
Output
对于每个第3种操作,给出正确的回答。
Sample Input
4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
Sample Output
2
【数据范围】
N<=50000,M<=100000。
重点----0号节点的初始化
否则有一个儿子为空的时候pushup 负数时会导致max值为不存在的0
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=50000+5; const int INF=0x3f3f3f;
int n,root,num,ls[N],rs[N],rnd[N],siz[N],val[N],add[N],maxx[N]; bool rev[N];
inline int make(int x)
{rnd[++num]=rand(); val[num]=maxx[num]=x; siz[num]=1; return num;}
inline void pass(int i,long long v)
{if(!i) return;
add[i]+=v; maxx[i]+=v; val[i]+=v;
}
inline void pushup(int i)
{siz[i]=siz[ls[i]]+siz[rs[i]]+1;
maxx[i]=max(val[i],max(maxx[ls[i]],maxx[rs[i]]));
}
inline void pushdown(int i)
{if(!i) return;
if(rev[i])
{rev[i]=0;
swap(ls[i],rs[i]);
if(ls[i]) rev[ls[i]]^=1;
if(rs[i]) rev[rs[i]]^=1;
}
if(add[i])
{pass(ls[i],add[i]);
pass(rs[i],add[i]);
add[i]=0;
}
}
void split(int now,int k,int &x,int &y)
{if(!now) {x=y=0;return;}
pushdown(now);
if(k<=siz[ls[now]])
{y=now; split(ls[now],k,x,ls[now]);
}
else
{x=now; split(rs[now],k-siz[ls[now]]-1,rs[now],y);
}
pushup(now);
}
int merge(int x,int y)
{if(!x || !y) return x+y;
pushdown(x); pushdown(y);
if(rnd[x]<=rnd[y])
{rs[x]=merge(rs[x],y);
pushup(x); return x;
}
else
{ls[y]=merge(x,ls[y]);
pushup(y); return y;
}
} /*
void print(int x)
{if(!x) return;
pushdown(x);
print(ls[x]);
printf("%d ",val[x]);
print(rs[x]);
}*/
int main()
{
int m,l,r,op,x,y,z,v; scanf("%d%d",&n,&m);
maxx[0]=-INF; //0号节点初始化
while(n--) {root=merge(root,make(0));}
while(m--)
{scanf("%d%d%d",&op,&l,&r);
split(root,r,x,y);
split(x,l-1,x,z);
if(op==1){scanf("%d",&v); pass(z,v); }
else if(op==2) rev[z]^=1;
else printf("%d\n",maxx[z]);
root=merge(merge(x,z),y);
// print(root); printf("\n");
}
return 0;
}