前言

学习于yyb

本来是想写个算法解释,克自己写了一半总感觉像复制的,各位就去yyb哪里学吧

这里附上几个BZOJ的模板题

\n

\n

\n

\n

练习1 BZOJ 3224 普通平衡树

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作

  • 插入 $x$ 数
  • 删除 $x$ 数(若有多个相同的数,因只删除一个)
  • 查询 $x$ 数的排名(排名定义为比当前数小的数的个数 $+1$ 。若有多个相同的数,因输出最小的排名)
  • 查询排名为 $x$ 的数
  • 求 $x$ 的前驱(前驱定义为小于 $x$ ,且最大的数)
  • 求 $x$ 的后继(后继定义为大于 $x$ ,且最小的数)

    splay的模板题

    也就是splay的全部操作

    前言的博客讲的很详尽了

    /**************************************************************
    Problem: 3224
    User: 3010651817
    Language: C++
    Result: Accepted
    Time:500 ms
    Memory:10672 kb
    ****************************************************************/ #include <cstdio>
    #include <iostream>
    #define maxN 400007
    using namespace std;
    inline int read() {
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while('0'<=s&&s<='9') {x=x*10+s-'0';s=getchar();}
    return x*f;
    }
    int root,tot;
    struct Node {
    int ch[2],val,ff,size,cnt;
    }t[maxN];
    inline void pushup(int u) {
    t[u].size=t[t[u].ch[0]].size+t[t[u].ch[1]].size+t[u].cnt;
    }
    inline void rotate(int x) { //核心操作->旋转
    int y=t[x].ff,z=t[y].ff,k=(t[y].ch[1]==x);
    t[z].ch[t[z].ch[1]==y]=x;//爷爷和儿子
    t[x].ff=z;
    t[y].ch[k]=t[x].ch[k^1];//爸爸和孙子
    t[t[x].ch[k^1]].ff=y;
    t[x].ch[k^1]=y;
    t[y].ff=x;//爸爸和儿子
    pushup(y);
    pushup(x);
    } inline void splay(int x,int goal) {
    while(t[x].ff!=goal) {
    int y=t[x].ff,z=t[y].ff;
    if(z!=goal)
    (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
    rotate(x);
    }
    if(!goal) root=x;
    }
    void find(int x) {
    int u=root;
    if(!u) return;
    while(t[u].ch[x>t[u].val]&&x!=t[u].val)
    u=t[u].ch[x>t[u].val];
    splay(u,0);
    }
    inline void insert(int x) {
    int u=root,ff=0;
    while(u&&t[u].val!=x) {
    ff=u;
    u=t[u].ch[x>t[u].val];
    }
    if(u)t[u].cnt++;
    else {
    u=++tot;
    if(ff)
    t[ff].ch[x>t[ff].val]=u;
    t[u].ch[0]=t[u].ch[1]=0;
    t[tot].ff=ff;
    t[tot].val=x;
    t[tot].cnt=1;
    t[tot].size=1;
    }
    splay(u,0);
    }
    int Next(int x,int f) {
    find(x);
    int u=root;
    if(t[u].val>x&&f) return u;
    if(t[u].val<x&&!f) return u;
    u=t[u].ch[f];
    while(t[u].ch[f^1])u=t[u].ch[f^1];
    return u;
    }
    void Delete(int x) {
    int last=Next(x,0);
    int nxt=Next(x,1);
    splay(last,0);
    splay(nxt,last);
    int del=t[nxt].ch[0];
    if(t[del].cnt>1) t[del].cnt--,splay(del,0);
    else t[nxt].ch[0]=0;
    }
    int k_th(int x) {
    int u=root;
    if(t[u].size<x) return 0;
    while(1) {
    int y=t[u].ch[0];
    if(x>t[y].size+t[u].cnt) {
    x-=t[y].size+t[u].cnt;
    u=t[u].ch[1];
    } else {
    if(t[y].size>=x)
    u=y;
    else
    return t[u].val;
    }
    }
    }
    int main()
    {
    int n=read();
    insert(0x7fffffff);
    insert(-0x7fffffff);
    while(n--)
    {
    int opt=read(),x=read();
    if(opt==1) insert(x);else
    if(opt==2) Delete(x);else
    if(opt==3) find(x),printf("%d\n",t[t[root].ch[0]].size);else
    if(opt==4) printf("%d\n",k_th(x+1));else
    if(opt==5) printf("%d\n",t[Next(x,0)].val);else
    if(opt==6) printf("%d\n",t[Next(x,1)].val);
    }
    return 0;
    }

    练习2 BZOJ 3223 文艺平衡树

    维护一个要m次区间翻转的区间,最后输出

    看题目一开始我还以为这是比普通的平衡树厉害的题目,但其实比普通的还简单的一个题

    区间翻转,只要范围内的左右节点全部互换就可以了

    这就可以类似于线段树的懒惰标记(原来splay也可以pushdown啊)

    建树的话,由于区间大小不变

    懒得直接套insert

    也可以写个build

    /**************************************************************
    Problem: 3223
    User: 3010651817
    Language: C++
    Result: Accepted
    Time:2288 ms
    Memory:14968 kb
    ****************************************************************/ #include <cstdio>
    #include <iostream>
    #define maxN 500007
    using namespace std;
    inline int read() {
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while('0'<=s&&s<='9') {x=x*10+s-'0';s=getchar();}
    return x*f;
    }
    int root,tot;
    struct Node {
    int ch[2],val,ff,size,cnt;
    int lazy;
    }t[maxN];
    inline void pushup(int u) {
    t[u].size=t[t[u].ch[0]].size+t[t[u].ch[1]].size+1;
    }
    void pushdown(int x)
    {
    if(t[x].lazy)
    {
    t[t[x].ch[0]].lazy^=1;
    t[t[x].ch[1]].lazy^=1;
    t[x].lazy=0;
    swap(t[x].ch[0],t[x].ch[1]);
    }
    }
    inline void rotate(int x) { //核心操作->旋转
    int y=t[x].ff,z=t[y].ff,k=(t[y].ch[1]==x);
    t[z].ch[t[z].ch[1]==y]=x;//爷爷和儿子
    t[x].ff=z;
    t[y].ch[k]=t[x].ch[k^1];//爸爸和孙子
    t[t[x].ch[k^1]].ff=y;
    t[x].ch[k^1]=y;
    t[y].ff=x;//爸爸和儿子
    pushup(x);
    pushup(y);
    } inline void splay(int x,int goal) {
    while(t[x].ff!=goal) {
    int y=t[x].ff,z=t[y].ff;
    if(z!=goal)
    (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
    rotate(x);
    }
    if(!goal) root=x;
    }
    inline void insert(int x) {
    int u=root,ff=0;
    while(u&&t[u].val!=x) {
    ff=u;
    u=t[u].ch[x>t[u].val];
    }
    u=++tot;
    if(ff)
    t[ff].ch[x>t[ff].val]=u;
    t[u].ch[0]=t[u].ch[1]=0;
    t[tot].ff=ff;
    t[tot].val=x;
    t[tot].cnt=1;
    t[tot].size=1;
    splay(u,0);
    }
    int k_th(int x) {
    int u=root;
    while(1) {
    pushdown(u);
    int y=t[u].ch[0];
    if(x>t[y].size+t[u].cnt) {
    x-=t[y].size+t[u].cnt;
    u=t[u].ch[1];
    } else {
    if(t[y].size>=x)
    u=y;
    else
    return t[u].val;
    }
    }
    }
    int n;
    inline void write(int x)
    {
    pushdown(x);
    if(t[x].ch[0])write(t[x].ch[0]);
    if(t[x].val>1&&t[x].val<n+2)printf("%d ",t[x].val-1);
    if(t[x].ch[1])write(t[x].ch[1]);
    }
    void work(int x,int y)
    {
    int l=k_th(x);
    int r=k_th(y+2);
    splay(l,0);
    splay(r,l);
    t[t[t[root].ch[1]].ch[0]].lazy^=1;
    }
    int main()
    {
    n=read();
    int m=read();
    for(int i=1;i<=n+2;++i) insert(i);
    while(m--)
    {
    int x=read(),y=read();
    work(x,y);
    }
    write(root);
    puts("");
    return 0;
    }

    练习3 BZOJ 1588 [HNOI2002]营业额统计

    求\(\sum_{1}^{n}\)最小波动值

    最小波动值=min{|该天以前某一天的营业额-该天营业额|}。

    很明显,最小波动值就是|该天营业额-他的前驱(<=)|

    或者|该天营业额-他的后继(>=)|

    两者取min就可以

    /**************************************************************
    Problem: 1588
    User: 3010651817
    Language: C++
    Result: Accepted
    Time:232 ms
    Memory:5048 kb
    ****************************************************************/ #include <cstdio>
    #include <iostream>
    #define maxN 160007
    using namespace std;
    inline int read() {
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while('0'<=s&&s<='9') {x=x*10+s-'0';s=getchar();}
    return x*f;
    }
    inline int abs(int a) {
    return a>0 ? a : -a;
    }
    int root,tot;
    struct Node {
    int ch[2],val,ff,size,cnt;
    }t[maxN];
    inline void pushup(int u) {
    t[u].size=t[t[u].ch[0]].size+t[t[u].ch[1]].size+t[u].cnt;
    }
    inline void rotate(int x) { //核心操作->旋转
    int y=t[x].ff,z=t[y].ff,k=(t[y].ch[1]==x);
    t[z].ch[t[z].ch[1]==y]=x;//爷爷和儿子
    t[x].ff=z;
    t[y].ch[k]=t[x].ch[k^1];//爸爸和孙子
    t[t[x].ch[k^1]].ff=y;
    t[x].ch[k^1]=y;
    t[y].ff=x;//爸爸和儿子
    pushup(x);
    pushup(y);
    } inline void splay(int x,int goal) {
    while(t[x].ff!=goal) {
    int y=t[x].ff,z=t[y].ff;
    if(z!=goal)
    (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
    rotate(x);
    }
    if(!goal) root=x;
    }
    void find(int x) {
    int u=root;
    if(!u) return;
    while(t[u].ch[x>t[u].val]&&x!=t[u].val)
    u=t[u].ch[x>t[u].val];
    splay(u,0);
    }
    inline void insert(int x) {
    int u=root,ff=0;
    while(u&&t[u].val!=x) {
    ff=u;
    u=t[u].ch[x>t[u].val];
    }
    if(u)t[u].cnt++;
    else {
    u=++tot;
    if(ff)
    t[ff].ch[x>t[ff].val]=u;
    t[u].ch[0]=t[u].ch[1]=0;
    t[tot].ff=ff;
    t[tot].val=x;
    t[tot].cnt=1;
    t[tot].size=1;
    }
    splay(u,0);
    }
    int Next(int x,int f) {
    int u=root; while(t[u].ch[x>t[u].val]&&x!=t[u].val)
    u=t[u].ch[x>t[u].val];
    if(x==t[u].val) return u;
    splay(u,0);
    u=root;
    if(t[u].val>x&&f) return u;
    if(t[u].val<x&&!f) return u;
    u=t[u].ch[f];
    while(t[u].ch[f^1])u=t[u].ch[f^1];
    return u;
    }
    int main()
    {
    //freopen("a.in","r",stdin);
    int n=read();
    insert(0x7fffffff);
    insert(-0x7fffffff);
    int tot=0;
    int x=read();
    int dsr=x;
    insert(x);
    tot+=x;
    x=read();
    insert(x);
    tot+=abs(x-dsr);
    for(int i=3;i<=n;++i)
    {
    x=read();
    int tmp1=t[Next(x,0)].val;
    int tmp2=t[Next(x,1)].val;
    insert(x);
    int ans=0x3f3f3f3f;
    if(tmp1!=-0x7fffffff)
    ans=min(ans,abs(tmp1-x));
    if(tmp2!=0x7fffffff)
    ans=min(ans,abs(tmp2-x));
    tot+=ans;
    //cout<<ans<<"\n";
    }
    printf("%d",tot);
    return 0;
    }

    练习4 BZOJ 1208 [HNOI2004]宠物收养场

    题目

    一开始读错了题(郝志章)

    很明显,题目想让你建两棵splay(s),但是

    如果一开始宠物多,领养者少,过渡到到宠物少,领养者多的情况的时候,一定会出现树上为空的情况,所以我们就只是用一颗树就可以了

    /**************************************************************
    Problem: 1208
    User: 3010651817
    Language: C++
    Result: Accepted
    Time:208 ms
    Memory:8800 kb
    ****************************************************************/ #include <cstdio>
    #include <iostream>
    #define mod 1000000
    #define inf 0x7fffffff
    #define maxN 320007
    using namespace std;
    int n;
    int tot_pet,tot_adopter;
    inline int min(int a,int b) {
    return a>b?b:a;
    }
    inline int abs(int a) {
    return a>0?a:-a;
    }
    inline int read() {
    int x=0,f=1;
    char s=getchar();
    while(s<'0'||s>'9') {
    if(s=='-')f=-1;
    s=getchar();
    }
    while('0'<=s&&s<='9') {
    x=x*10+s-'0';
    s=getchar();
    }
    return x*f;
    }
    int root,tot;
    struct Node {
    int ch[2],val,ff,size,cnt;
    } t[maxN];
    inline void pushup(int u) {
    t[u].size=t[t[u].ch[0]].size+t[t[u].ch[1]].size+t[u].cnt;
    }
    inline void rotate(int x) {
    int y=t[x].ff,z=t[y].ff,k=(t[y].ch[1]==x);
    t[z].ch[t[z].ch[1]==y]=x;
    t[x].ff=z;
    t[y].ch[k]=t[x].ch[k^1];
    t[t[x].ch[k^1]].ff=y;
    t[x].ch[k^1]=y;
    t[y].ff=x;
    pushup(x);
    pushup(y);
    }
    inline void splay(int x,int goal) {
    while(t[x].ff!=goal) {
    int y=t[x].ff,z=t[y].ff;
    if(z!=goal)
    (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
    rotate(x);
    }
    if(!goal) root=x;
    }
    void find(int x) {
    int u=root;
    if(!u) return;
    while(t[u].ch[x>t[u].val]&&x!=t[u].val)
    u=t[u].ch[x>t[u].val];
    splay(u,0);
    }
    inline void insert(int x) {
    int u=root,ff=0;
    while(u&&t[u].val!=x) {
    ff=u;
    u=t[u].ch[x>t[u].val];
    }
    if(u)t[u].cnt++;
    else {
    u=++tot;
    if(ff)
    t[ff].ch[x>t[ff].val]=u;
    t[u].ch[0]=t[u].ch[1]=0;
    t[tot].ff=ff;
    t[tot].val=x;
    t[tot].cnt=1;
    t[tot].size=1;
    }
    splay(u,0);
    }
    int Next(int x,int f) {
    find(x);
    int u=root;
    if(t[u].val>x&&f) return u;
    if(t[u].val<x&&!f) return u;
    u=t[u].ch[f];
    while(t[u].ch[f^1])u=t[u].ch[f^1];
    return u;
    }
    void Delete(int x) {
    int last=Next(x,0);
    int nxt=Next(x,1);
    splay(last,0);
    splay(nxt,last);
    int del=t[nxt].ch[0];
    if(t[del].cnt>1) t[del].cnt--,splay(del,0);
    else t[nxt].ch[0]=0;
    }
    inline int check(int x) {
    int u=root;
    if(!u) return -1;
    while(t[u].ch[x>t[u].val]&&x!=t[u].val)
    u=t[u].ch[x>t[u].val];
    if(x==t[u].val) return u;
    return -1;
    }
    //维护一颗splay就可以
    //如果一开始宠物多,人少,之后如果宠物少,人多的话 ,splay树必须先为空
    //这样就可以重复利用了
    int main() { n=read();
    insert(inf);
    insert(-inf);
    int tot=0;
    while(n--) {
    int a=read(),b=read();
    if(a) { //adopter
    if(tot_pet) { //还有宠物
    tot_pet--;
    int zz=check(b);
    if(zz!=-1) {
    Delete(t[zz].val);
    continue;
    }//检查一下有没有前面等于自己的宠物
    int ans=inf;
    int tmp1=Next(b,0);//前驱,注意是标号!!!
    int tmp2=Next(b,1);//后继
    //cout<<t[tmp1].val<<" "<<t[tmp2].val<<"\n";
    if(t[tmp1].val==-inf) {//没有前驱
    tot+=abs(b-t[tmp2].val);
    tot%=mod;
    Delete(t[tmp2].val);
    //continue;
    } else if(t[tmp2].val==inf) { //没有后缀
    tot+=abs(b-t[tmp1].val);
    tot%=mod;
    Delete(t[tmp1].val);
    //continue;
    } else if(abs(b-t[tmp1].val) > abs(b-t[tmp2].val)) {
    tot+=abs(b-t[tmp2].val);
    tot%=mod;
    Delete(t[tmp2].val);
    } else {
    tot+=abs(b-t[tmp1].val);
    tot%=mod;
    Delete(t[tmp1].val);
    }
    } else {
    insert(b);
    tot_adopter++;
    }
    } else { //pet
    if(tot_adopter) { //还有领养者
    tot_adopter--;
    int zz=check(b);
    if(zz!=-1) {
    Delete(t[zz].val);
    continue;
    }//检查一下有没有前面等于自己的宠物
    int ans=inf;
    int tmp1=Next(b,0);//前驱,注意是标号!!!
    int tmp2=Next(b,1);//后继
    //cout<<t[tmp1].val<<" "<<t[tmp2].val<<"\n";
    if(t[tmp1].val==-inf) {//没有前驱
    tot+=abs(b-t[tmp2].val);
    tot%=mod;
    Delete(t[tmp2].val);
    continue;
    }
    if(t[tmp2].val==inf) {//没有后缀
    tot+=abs(b-t[tmp1].val);
    tot%=mod;
    Delete(t[tmp1].val);
    continue;
    }
    if(abs(b-t[tmp1].val) > abs(b-t[tmp2].val)) {
    tot+=abs(b-t[tmp2].val);
    tot%=mod;
    Delete(t[tmp2].val);
    } else {
    tot+=abs(b-t[tmp1].val);
    tot%=mod;
    Delete(t[tmp1].val);
    }
    } else { //adopter空了
    insert(b);
    tot_pet++;
    }
    }
    }
    printf("%d\n",tot);
    return 0;
    }

    练习5 BZOJ 1507 [NOI2003]文本编辑器 editor

    题目

    注意:luogu的朋友,输入需要注意\r

    输出的话,把l到r的子树旋到root右儿子的左儿子上,然后中序遍历

    删除l到r的子树的子树,旋转和输出类似

    感兴趣的朋友还可以看看

    BZOJ 1269(非重题) [AHOI2006]文本编辑器editor

    这个

    /**************************************************************
    Problem: 1507
    User: 3010651817
    Language: C++
    Result: Accepted
    Time:2128 ms
    Memory:54028 kb
    ****************************************************************/ #include <iostream>
    #include <cstdio>
    #define maxn 3000001
    using namespace std;
    int read()
    {
    int x=0,f=1;char s=getchar();
    while('0'>s||s>'9'){
    if(s=='-')f=-1;
    s=getchar();
    }
    while('0'<=s&&s<='9') {
    x=x*10+s-'0';
    s=getchar();
    }
    return x*f;
    }
    int n,cnt,root,mouse;
    int fa[maxn],ch[maxn][2],siz[maxn];
    char w[maxn];
    void update(int x) {
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    }
    int get(int x) {
    return ch[fa[x]][1]==x;
    }
    void rotate(int x) {
    int f=fa[x],ff=fa[f],son=get(x);
    ch[f][son]=ch[x][son^1];
    if(ch[f][son]) fa[ch[f][son]]=f;
    fa[f]=x;
    ch[x][son^1]=f;
    fa[x]=ff;
    if(ff) ch[ff][ch[ff][1]==f]=x;
    update(f);
    update(x);
    }
    void splay(int x,int to) {
    if(x==to||fa[x]==to) return;
    if(to==0) root=x;
    for(int f; (f=fa[x])&&(f!=to); rotate(x)) {
    if(fa[f]!=to)
    rotate(get(x)==get(f)?f:x);
    }
    update(x);
    }
    int rank(int x,int pos) {
    if(siz[ch[pos][0]]+1==x) {
    splay(pos,0);
    return pos;
    }
    if(siz[ch[pos][0]]>=x) return rank(x,ch[pos][0]);
    else return rank(x-siz[ch[pos][0]]-1,ch[pos][1]);
    }
    char s[maxn];
    int build(int l,int r,int f) {
    if(l>r) return 0;
    int mid=(l+r)>>1,cur=++cnt;
    fa[cur]=f;
    w[cur]=s[mid];
    ch[cur][0]=build(l,mid-1,cur);
    ch[cur][1]=build(mid+1,r,cur);
    update(cur);
    return cur;
    }
    void insert(int l,int len) {
    int x=rank(l,root),y=rank(l+1,root);
    splay(x,0);
    splay(y,root);
    ch[y][0]=build(1,len,y);
    update(y);
    update(x);
    }
    void del(int l,int r) {
    int x=rank(l,root),y=rank(r+2,root);
    splay(x,0);
    splay(y,root);
    ch[y][0]=0;
    update(y);
    update(x);
    }
    void dfs(int x) {
    if(!x) return ;
    dfs(ch[x][0]);
    printf("%c",w[x]);
    dfs(ch[x][1]);
    }
    void print(int l,int len) {
    int x=rank(l,root),y=rank(l+len+1,root);
    splay(x,0);
    splay(y,root);
    dfs(ch[y][0]);
    puts("");
    }
    int main() {
    int i,j,t1;
    char op[10];
    char c;
    n=read(); root=++cnt;
    w[cnt]=0;
    siz[cnt]=2;
    ch[cnt][1]=cnt+1;
    cnt++;
    fa[cnt]=cnt-1;
    w[cnt]=0;
    siz[cnt]=1;
    mouse=1;
    for(i=1; i<=n; i++) {
    scanf("%s",op);
    if(op[0]=='I') {
    t1=read();
    for(j=1; j<=t1; j++) {
    c=getchar();
    while(c=='\n'||c=='\r') c=getchar();//超级大坑
    s[j]=c;
    }
    insert(mouse,t1);
    }
    if(op[0]=='D') {
    t1=read();
    del(mouse,mouse+t1-1);
    }
    if(op[0]=='G') {
    t1=read();
    print(mouse,t1);
    }
    if(op[0]=='M') {
    t1=read();
    mouse=t1+1;
    }
    if(op[0]=='N') mouse++;
    if(op[0]=='P') mouse--;
    }
    }

    练习6 BZOJ 1503 [NOI2004]郁闷的出纳员

    题目

    由于是全体降工资,涨工资,所以不用lazy,不用改树

    直接把标准改一下就,但加入新人的时候,也需要把它的工资改一下。

    (标准都改,新人也需要同步)

    然后降工资的时候删除一下标准的1到标准前缀的子树就可以了

    这里查询第k多工资,而不是第k小,所以需要 员工总数-k+1

    /**************************************************************
    Problem: 1503
    User: 3010651817
    Language: C++
    Result: Accepted
    Time:784 ms
    Memory:3872 kb
    ****************************************************************/ #include <iostream>
    #include <cstdio>
    #define INF 0x3f3f3f3f
    #define maxn 110000
    using namespace std;
    int n,root;
    struct Node {
    int ch[2];
    int val;
    int ff;
    int cnt;
    int size;
    } t[maxn];
    int tot,mm,ans,add;
    inline void pushup(int x) {
    t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+t[x].cnt;
    }
    inline void rotate(int x) {
    int y=t[x].ff,z=t[y].ff,k=(x==t[y].ch[1]);
    t[z].ch[y==t[z].ch[1]]=x;
    t[x].ff=z;
    t[y].ch[k]=t[x].ch[k^1];
    t[t[x].ch[k^1]].ff=y;
    t[x].ch[k^1]=y;
    t[y].ff=x;
    pushup(y);
    pushup(x);
    }
    inline void splay(int x,int goal) {
    while(t[x].ff!=goal) {
    int y=t[x].ff;
    int z=t[y].ff;
    if(z!=goal)
    (t[z].ch[0]==y)^(t[y].ch[0]==x)? rotate(x):rotate(y);
    rotate(x);
    }
    if(!goal) root=x;
    }
    void find(int x) {
    int u=root;
    if(!u) return;
    while(t[u].ch[x>t[u].val]&&x!=t[u].val)
    u=t[u].ch[x>t[u].val];
    splay(u,0);
    }
    inline void insert(int x) {
    int u=root,ff=0;
    while(u&&t[u].val!=x) {
    ff=u;
    u=t[u].ch[x>t[u].val];
    }
    if(u)t[u].cnt++;
    else {
    u=++tot;
    if(ff)
    t[ff].ch[x>t[ff].val]=u;
    t[u].ch[0]=t[u].ch[1]=0;
    t[tot].ff=ff;
    t[tot].val=x;
    t[tot].cnt=1;
    t[tot].size=1;
    }
    splay(u,0);
    }
    inline int Next(int x,int f) {
    find(x);
    int u=root;
    if(t[u].val>=x&&f)return u;
    if(t[u].val<=x&&!f)return u;
    u=t[u].ch[f];
    while(t[u].ch[f^1])u=t[u].ch[f^1];
    return u;
    } int k_th(int x) {
    int u=root;
    if(t[u].size<x||x<1) return -INF;
    while(1) {
    int y=t[u].ch[0];
    if(x>t[y].size+t[u].cnt) {
    x-=t[y].size+t[u].cnt;
    u=t[u].ch[1];
    } else {
    if(t[y].size>=x)
    u=y;
    else
    return t[u].val;
    }
    }
    } int main() {
    insert(+INF);
    scanf("%d%d",&n,&mm);
    int peo=0;
    while(n--) {
    int x;
    char ch[3];
    scanf("%s%d",ch,&x);
    if(ch[0]=='I') {
    if(x>=mm) {
    insert(x-add);
    peo++;
    }
    }
    if(ch[0]=='A')
    add+=x;
    if(ch[0]=='S') {
    add-=x;
    int gg=Next(mm-add,1);
    splay(gg,0);
    ans+=t[t[root].ch[0]].size;
    peo-=t[t[root].ch[0]].size;
    t[t[root].ch[0]].size=t[t[root].ch[0]].cnt=0;
    t[root].ch[0]=0;
    t[0].size=0;
    pushup(root);
    }
    if(ch[0]=='F') {
    int gg=k_th(peo-x+1);
    printf("%d\n",gg==-INF?-1:(gg+add));
    }
    }
    printf("%d\n",ans);
    return 0;
    }
    /*
    思路一样,可惜自己D了2小时没弄出来╮(╯_╰)╭太弱了
    */
    

    平衡树之伸展树(Splay Tree)题目整理的更多相关文章

    1. 纸上谈兵: 伸展树 (splay tree)[转]

      作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!  我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每 ...

    2. 树-伸展树(Splay Tree)

      伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...

    3. K:伸展树(splay tree)

        伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...

    4. 高级搜索树-伸展树(Splay Tree)

      目录 局部性 双层伸展 查找操作 插入操作 删除操作 性能分析 完整源码 与AVL树一样,伸展树(Splay Tree)也是平衡二叉搜索树的一致,伸展树无需时刻都严格保持整棵树的平衡,也不需要对基本的 ...

    5. 【BBST 之伸展树 (Splay Tree)】

      最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...

    6. 伸展树(Splay tree)的基本操作与应用

      伸展树的基本操作与应用 [伸展树的基本操作] 伸展树是二叉查找树的一种改进,与二叉查找树一样,伸展树也具有有序性.即伸展树中的每一个节点 x 都满足:该节点左子树中的每一个元素都小于 x,而其右子树中 ...

    7. 伸展树 Splay Tree

      Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...

    8. HDU 4453 Looploop (伸展树splay tree)

      Looploop Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

    9. hdu 2871 Memory Control(伸展树splay tree)

      hdu 2871 Memory Control 题意:就是对一个区间的四种操作,NEW x,占据最左边的连续的x个单元,Free x 把x单元所占的连续区间清空 , Get x 把第x次占据的区间输出 ...

    10. [Splay伸展树]splay树入门级教程

      首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...

    随机推荐

    1. 2018/04/02 每日一个Linux命令 之 新建/修改/删除群组

      -- 新建群组 groupadd [群组名] -- 修改群组名称 groupmod [群组名] [新群组名] -n 修改组名 -g 修改组识别码 -- 删除群组 groupdel [删除的组名] --

    2. seajs引入jquery为什么无效?

      简单来说,你的jquery没有模块化? 答案:传送门1.传送门2

    3. Hibernate错误

      1.Field 'id' doesn't have a default value 原来是我的数据设计的时候,把主键的类型定义为int的,原本想是用自增的方式来的,可是由于自己的粗心,写sql语句的时 ...

    4. Java学习之路-RMI学习

      Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序可以调用远 ...

    5. [LeetCode] 38. Count and Say_Easy

      The count-and-say sequence is the sequence of integers with the first five terms as following: 1. 1 ...

    6. 训练/验证/测试集设置;偏差/方差;high bias/variance;正则化;为什么正则化可以减小过拟合

      1. 训练.验证.测试集 对于一个需要解决的问题的样本数据,在建立模型的过程中,我们会将问题的data划分为以下几个部分: 训练集(train set):用训练集对算法或模型进行训练过程: 验证集(d ...

    7. 梯度消失与梯度爆炸 ==> 如何选择随机初始权重

      梯度消失与梯度爆炸 当训练神经网络时,导数或坡度有时会变得非常大或非常小,甚至以指数方式变小,这加大了训练的难度 这里忽略了常数项b.为了让z不会过大或者过小,思路是让w与n有关,且n越大,w应该越小 ...

    8. numpy的ravel()和flatten()函数

      相同点: 两者所要实现的功能是一致的(将多维数组降位一维).这点从两个单词的意也可以看出来,ravel(散开,解开),flatten(变平). In [14]: x=np.array([[1,2],[ ...

    9. windows下编译和安装boost库

      boost是一个功能强大.构造精巧.跨平台.开源并且完全免费的C++程序库. 获取方式 boost提供源码形式的安装包,可以从boost官方网站下载,目前最新版本是1.59.0. 本机上正好有boos ...

    10. java实现Comparable接口和Comparator接口,并重写compareTo方法和compare方法

      原文地址https://segmentfault.com/a/1190000005738975 实体类:java.lang.Comparable(接口) + comareTo(重写方法),业务排序类 ...