各位大佬講得真好 我既然講不好就不講了
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;
}