整理的算法模板合集: ACM模板
FQH - treap 非旋平衡树
operator 1 : 插入一个数
operator 2 : 删除一个数
operator 3 : 通过数值找排名
operator 4 : 通过排名找数值
operator 5 : 找到严格小于key的最大数(前驱)
operator 6 : 找到严格大于key的最小数(后继)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<time.h>
using namespace std;
const int N = 500007;
namespace treap{//!FHQ_Treap
struct node{
int l, r;
int size;
int val, fix;
}tr[500007];
int tot;
int x, y, z, root;
inline void pushup(int p)
{
tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + 1;
}
inline int get_node(int val)
{
tr[ ++ tot].size = 1;
tr[tot].val = val;
tr[tot].fix = rand();
return tot;
}
inline int merge(int x, int y)
{
if(!x || !y)return x + y;
if(tr[x].fix > tr[y].fix){
tr[x].r = merge(tr[x].r, y);pushup(x);return x;}
else {tr[y].l = merge(x, tr[y].l);pushup(y);return y;}
}
//x <= k y > k
inline void split(int p, int k, int &x, int &y)//!xy最开始是谁无所谓,拆完之后要用谁而已
{
if(!p) {x = y = 0;return ;}
if(tr[p].val <= k) x = p, split(tr[p].r, k, tr[p].r, y);
else y = p, split(tr[p].l, k, x, tr[p].l);
pushup(p);
}
inline int k_th(int p, int k)//找到第k个数的编号
{
while(1){
if(k <= tr[tr[p].l].size)p = tr[p].l;
else if(k == tr[tr[p].l].size + 1)return p;
else k -= tr[tr[p].l].size + 1, p = tr[p].r;
}
}
inline void ins(int k)
{
split(root, k, x, y);
root = merge(merge(x, get_node(k)), y);
}
inline void del(int k)
{
split(root, k, x, z);
split(x, k - 1, x, y);
y = merge(tr[y].l, tr[y].r);
root = merge(merge(x, y), z);
}
inline void get_rank(int k)
{
split(root, k - 1, x, y);
printf("%d\n", tr[x].size + 1);
root = merge(x, y);
}
inline void get_key(int k)
{
printf("%d\n", tr[k_th(root, k)].val);
}
inline void get_prev(int k)
{
split(root, k - 1, x, y);
printf("%d\n", tr[k_th(x, tr[x].size)].val);
root = merge(x, y);
}
inline void get_next(int k)
{
split(root, k, x, y);
printf("%d\n", tr[k_th(y, 1)].val);
root = merge(x, y);
}
inline void main(){
srand((unsigned)time(NULL));
memset(tr, 0, sizeof tr);
}
}
int T;
int op, a;
int main()
{
scanf("%d", &T);
treap::main();
while(T -- ){
scanf("%d%d", &op, &a);
if(op == 1)treap::ins(a);
else if(op == 2)treap::del(a);
else if(op == 3)treap::get_rank(a);
else if(op == 4)treap::get_key(a);
else if(op == 5)treap::get_prev(a);
else treap::get_next(a);
}
return 0;
}
文艺平衡树
维护一个有序序列,经过m次区间操作:翻转一个区间,例如原有序序列是 ,翻转区间是 的话,结果是 ,要求最后输出整个序列
/*平衡树实际上画出来是一颗乱糟糟的小根堆,但是满足小根堆的性质,
所以我们这里区间翻转,找到区间需要按照排名split,
只需要在这个区间里一直交换左右儿子即可实现区间翻转*/
/*最后中序遍历输出值即可*/
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 500007;
int n, m, root;
namespace treap{
int n, m, tot;
struct tree{
int l, r;
int fix;
int val;
int size;
int lz;
}tr[500007];
inline int get_node(int v)
{
tr[++ tot].val = v;
tr[tot].size = 1;
tr[tot].fix = rand();
return tot;
}
void pushdown(int p)//下传懒标记,注意先交换,再下传
{
if(tr[p].lz){
swap(tr[p].l, tr[p].r);
tr[tr[p].l].lz ^= 1;
tr[tr[p].r].lz ^= 1;
tr[p].lz = 0;
}
}
void pushup(int p)
{
tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + 1;
}
void split(int p, int rnk, int &x, int &y)
{
if(!p){x = y = 0;return ;}
pushdown(p);
//合并左边,往右边走
if(tr[tr[p].l].size + 1 <= rnk)x = p,split(tr[p].r, rnk - tr[tr[p].l].size - 1, tr[p].r, y);
else y = p, split(tr[p].l, rnk, x, tr[p].l);
pushup(p);
}
int merge(int x, int y)
{
if(!x || !y)return x + y;
if(tr[tr[x].l].fix < tr[tr[y].l].fix)
{
pushdown(x);
tr[x].r = merge(tr[x].r, y);
pushup(x);
return x;
}
else {
pushdown(y);
tr[y].l = merge(x, tr[y].l);
pushup(y);
return y;
}
}
void print(int p)//必须要中序遍历才能输出答案
{
pushdown(p);
if(tr[p].l)//左
print(tr[p].l);
printf("%d ",tr[p].val);//中
if(tr[p].r)//右
print(tr[p].r);
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++ i)
{
root = treap::merge(root, treap::get_node(i));
}
for(int i = 1, l, r, x, y, p; i <= m; ++ i)
{
scanf("%d%d", &l, &r);
treap::split(root, r, x, y);
treap::split(x, l - 1, x, p);
treap::tr[p].lz ^= 1;
root = treap::merge(treap::merge(x, p), y);
}
treap::print(root);
return 0;
}
可持久化序列
求支持三个操作:
1 l r
,翻转l到r的区间;
2 l r
,询问l的到r的区间和;
3 p
,回到p时刻。
每次修改新建点打翻转标记即可
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<algorithm>
using namespace std;
typedef pair<int,int> Pair;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=5e4+5;
const int nlogn=1.3e7+5;
struct node {
int x,hp,l,r,sum,size;
bool rev;
void clear() {
x=hp=l=r=sum=size=rev=0;
}
};
struct TREAP {
int pool[nlogn];
int pooler;
node t[nlogn];
int now,all;
int root[maxn];
TREAP ():now(0),pooler(1) {
for (int i=1;i<nlogn;++i) pool[i]=i;
root[now]=pool[pooler++];
}
int newroot() {
int ret=pool[pooler++];
return ret;
}
int newnode(int x) {
int ret=pool[pooler++];
t[ret].hp=rand();
t[ret].size=1;
t[ret].x=t[ret].sum=x;
return ret;
}
void delnode(int x) {
t[x].clear();
pool[--pooler]=x;
}
void next() {
root[++all]=newroot();
t[root[all]]=t[root[now]];
now=all;
}
void back(int x) {
now=x;
}
void update(int x) {
t[x].sum=t[x].x+t[t[x].l].sum+t[t[x].r].sum;
t[x].size=t[t[x].l].size+t[t[x].r].size+1;
}
void pushdown(int x) {
if (!t[x].rev) return;
if (t[x].l) {
int tx=newnode(t[t[x].l].x);
t[tx]=t[t[x].l];
t[tx].rev^=true;
t[x].l=tx;
}
if (t[x].r) {
int tx=newnode(t[t[x].r].x);
t[tx]=t[t[x].r];
t[tx].rev^=true;
t[x].r=tx;
}
swap(t[x].l,t[x].r);
t[x].rev=false;
}
int merge(int x,int y) {
if (!x) return y;
if (!y) return x;
int now;
if (t[x].hp<=t[y].hp) {
now=newnode(t[x].x);
t[now]=t[x];
pushdown(now);
t[now].r=merge(t[now].r,y);
} else {
now=newnode(t[y].x);
t[now]=t[y];
pushdown(now);
t[now].l=merge(x,t[now].l);
}
update(now);
return now;
}
Pair split(int x,int p) {
if (t[x].size==p) return make_pair(x,0);
int now=newnode(t[x].x);
t[now]=t[x];
pushdown(now);
int l=t[now].l,r=t[now].r;
if (t[l].size>=p) {
t[now].l=0;
update(now);
Pair g=split(l,p);
now=merge(g.second,now);
return make_pair(g.first,now);
} else if (t[l].size+1==p) {
t[now].r=0;
update(now);
return make_pair(now,r);
} else {
t[now].r=0;
update(now);
Pair g=split(r,p-t[l].size-1);
now=merge(now,g.first);
pushdown(now);
return make_pair(now,g.second);
}
}
void rever(int l,int r) {
++l,++r;
Pair g=split(root[now],l-1);
Pair h=split(g.second,r-l+1);
int want=h.first;
int here=newnode(t[want].x);
t[here]=t[want];
t[here].rev^=true;
int fi=merge(g.first,here);
int se=merge(fi,h.second);
root[now]=se;
}
int query(int l,int r) {
++l,++r;
Pair g=split(root[now],l-1);
Pair h=split(g.second,r-l+1);
int want=h.first;
int ret=t[want].sum;
int fi=merge(g.first,want);
int se=merge(fi,h.second);
root[now]=se;
return ret;
}
void insert(int x) {
int k=newnode(x);
root[now]=merge(root[now],k);
}
} Treap;
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("my.out","w",stdout);
#endif
srand(time(0));
int n=read(),m=read();
for (int i=1;i<=n;++i) {
int x=read();
Treap.insert(x);
}
while (m--) {
int op=read();
if (op==1) {
Treap.next();
int l=read(),r=read();
Treap.rever(l,r);
} else if (op==2) {
int l=read(),r=read();
int ans=Treap.query(l,r);
printf("%d\n",ans);
} else if (op==3) {
Treap.back(read());
}
}
return 0;
}