splay操作集合

来源:互联网 发布:淘宝居家日用类目 编辑:程序博客网 时间:2024/06/05 18:41

下传标记

void back(ll x,ll y){    a[x]+=y,ans[x]+=y,add[x]+=y;}

更新当前点的答案

void update(ll x){    ans[x]=max(a[x],max(ans[tr[x][0]],ans[tr[x][1]]));}

把标记传给儿子

void clear(ll x){    if (tr[x][0]) back(tr[x][0],add[x]);    if (tr[x][1]) back(tr[x][1],add[x]);    add[x]=0;}

判断点x是它父亲的左儿子还是右儿子

ll son(ll x){    return tr[fa[x]][1]==x;}

把x旋到x的父亲

void rotate(ll x){    ll k=son(x),y=fa[x];    if (tr[x][!k]) fa[tr[x][!k]]=y;    if (fa[y]) tr[fa[y]][son(y)]=x;    fa[x]=fa[y],fa[y]=x,tr[y][k]=tr[x][!k],tr[x][!k]=y;    update(y),update(x);}

释放从x到y的标记

void remove(ll x,ll y){    d[0]=0;    while (x!=y){        d[++d[0]]=x,x=fa[x];    }    while (d[0]) clear(d[d[0]--]);}

把x旋到y的儿子

void splay(ll x,ll y){    remove(x,y);    while (fa[x]!=y){        if (fa[fa[x]]!=y)            rotate((son(x)==son(fa[x]))?fa[x]:x);        rotate(x);    }}

查找排名为x的点

ll find(ll x){    ll rk=0,nw=rt;    while (1){        if (tr[nw][0] && siz[tr[nw][0]]+rk>=x) nw=tr[nw][0];else{            rk+=siz[tr[nw][0]];            if (rk+1==x){                splay(nw,0);                rt=nw;                return nw;            }            rk+=1,nw=tr[nw][1];        }    }}

查询区间x,y

if (ch=='Q'){            scanf("uery%lld%lld\n",&l,&r);            l++,r++;            x=find(l-1);            y=find(r+1);            splay(x,0);            rt=x;            splay(y,x);            printf("%lld\n",(ans[tr[y][0]]+mo)%mo);        }

在区间x,y中+z

if (ch=='A'){            scanf("dd%lld%lld%lld\n",&l,&r,&z);            l++,r++;            x=find(l-1),y=find(r+1);            splay(x,0),splay(y,x);            rt=x;            back(tr[y][0],z);        }

在x前插入y

if (ch=='I'){            scanf("nsert%lld%lld\n",&l,&r);            x=find(l);            y=find(l+1);            splay(x,0),splay(y,x);            rt=x;            tr[y][0]=++n;            fa[n]=y;            a[n]=r;            p[n]=r*r%mo;            update(n);            splay(n,0);            rt=n;        }
原创粉丝点击