/*注意:
1、看平衡树之前你要注意,对于1 3 5 3 2这一组数据。sz的值是4,因为sz保存的是节点种类
为什么要这样,因为sz涉及到要为几个点开空间
2、sizes[x]保存的是以x为树根的子树上节点数量,比如x这颗子树所有节点为1,2,1.那么它的sizes[x]=3
而且实际上不会有两个1放在树上。而是给1的权值数组cnt[1]加1
3、对于1 3 5 3 2这一组数据。sz的值是4。那么1对应位置就是1,3对应位置就是2,5对应位置就是3,2对应位置就是4
之后他们所对应的位置都不会改变
在平衡树旋转的过程中只是每一个点的儿子节点ch[x][0]和ch[x][1]里面保存的值在改变*/#include#include#include#include
using namespacestd;const int maxn=1e5+10;
typedeflong longll;
ll f[maxn],cnt[maxn],ch[maxn][2],sizes[maxn],key[maxn],sz,rt;/*f[i]:i节点的父节点,cnt[i]每个点出现的次数,ch[i][0/1]:0表示左孩子,
1表示右孩子, size[i]表示以i为根节点的子树的节点个数
key[i]表示点i代表的数的值;sz为整棵树的节点种类数,rt表示根节点*/
void clears(ll x) //删除x点信息
{
f[x]=cnt[x]=ch[x][0]=ch[x][1]=sizes[x]=key[x]=0;
}bool get(ll x) //判断x是父节点的左孩子还是右孩子
{return ch[f[x]][1]==x; //返回1就是右孩子,返回0就是左孩子
}void pushup(ll x) //重新计算一下x这棵子树的节点数量
{if(x)
{
sizes[x]=cnt[x];if(ch[x][0]) sizes[x]+=sizes[ch[x][0]];if(ch[x][1]) sizes[x]+=sizes[ch[x][1]];
}
}void rotates(ll x) //将x移动到他父亲的位置,并且保证树依旧平衡
{
ll fx=f[x],ffx=f[fx],which=get(x);//x点父亲,要接受x的儿子。而且x与x父亲身份交换
ch[fx][which]=ch[x][which^1];
f[ch[fx][which]]=fx;
ch[x][which^1]=fx;