zoukankan      html  css  js  c++  java
  • 伸展树复习

    T1 郁闷的出纳员

    一个数据结构,支持单点插入、删除几个不一定连续的点、查询k值操作

    初做:2017.2.18   time:1268ms    memory:3MB

    http://www.cnblogs.com/TheRoadToTheGold/p/6412790.html

    现在:2017.3.28   time:570ms   memory:3MB

    初做时直接套模板,删除分5种情况,

    本题实际只需3种情况

    这一次的查询用递归写的

    int query(int now,int k)
    {
    	int tmp=0;
    	if(ch[now][0]) tmp=sum[ch[now][0]];
    	if(k<=tmp) return query(ch[now][0],k);
    	if(tmp+cnt[now]>=k) return key[now];
    	return query(ch[now][1],k-tmp-cnt[now]);
    }
    

    5行开始写的时候每一行都有错误

    第二行:tmp=左子树节点个数,遗漏了判断是否有左子树

    第三行:当k<=左子树节点个数,漏了等于号

    第四行:左子树节点个数+根节点个数(cnt[]数组)>=k,cnt[]和sum[]混了,>写的<

    第五行:cnt和sum混了

    再就是splay写丑了

    贴个精简的:

    inline void splay(int x)
    {
        for(int fa;fa=f[x];rotate(x))
          if(f[fa]) rotate(getson(x)==getson(fa) ? fa:x);
        root=x;
        update(x);
    }

    一定要注意update时节点是否有左右孩子

    rotate里出现了一个错误:

    if(z) ch[z][ch[z][1]==y]=x;

    fa[x]=z;这一句是不在if(z)里的

    #include<cstdio>
    #define N 100001
    using namespace std;
    int n,limit,gather,root,tot,leave;
    int sum[N],ch[N][2],fa[N],key[N],cnt[N];
    void newroot(int x)
    {
        sum[++tot]=cnt[tot]=1;
        key[tot]=x;
        root=tot;
    }
    void newnode(int f,int x)
    {
        sum[++tot]=cnt[tot]=1;
        key[tot]=x;
        fa[tot]=f;
        ch[f][x>key[f]]=tot;
    }
    void update(int x)
    {
        sum[x]=cnt[x];
        if(ch[x][0]) sum[x]+=sum[ch[x][0]];
        if(ch[x][1]) sum[x]+=sum[ch[x][1]];
    }
    void rotate(int x,int kind)
    {
        int y=fa[x],z=fa[y];
        ch[y][!kind]=ch[x][kind]; fa[ch[y][!kind]]=y;
        ch[x][kind]=y;fa[y]=x;
        fa[x]=z;
        if(z) ch[z][ch[z][1]==y]=x;
        update(y);
    }
    void splay(int x)
    {
        while(fa[x])
        {
            int y=fa[x],kind=ch[y][1]==x;
            if(!fa[y]) rotate(x,!kind);
            else
            {
                int z=ch[fa[y]][1]==y;
                if(z==kind) 
                {
                    rotate(y,!kind);
                    rotate(x,!kind);
                }
                else
                {
                    rotate(x,!kind);
                    rotate(x,kind);
                }
            }
        }
        update(x);
        root=x;
    }
    void insert(int x)
    {
        if(!root) 
        {
            newroot(x);
            return;
        }
        int now=root;
        while(ch[now][x>key[now]])
        {
            if(key[now]==x)
            {
                cnt[now]++;
                update(now);
                splay(now);
                return;
            }
            now=ch[now][x>key[now]];
        }
        if(key[now]==x)
        {
            cnt[now]++;
            update(now);
            splay(now);
            return;
        }
        newnode(now,x);
        update(now);
        splay(tot);
    }
    void cut_lch()
    {
        int tmp=ch[root][0];
        if(tmp) leave+=sum[tmp];
        fa[tmp]=0; ch[root][0]=0;
        update(root);
    }
    void cut()
    {
        if(cnt[root]>1)
        {
            cnt[root]--;
            update(root);
            return;
        }
        if(!ch[root][1])
        {
            root=0;
            gather=0;
            return;
        }
        int tmp=ch[root][1];
        fa[tmp]=0;
        ch[root][1]=0;
        root=tmp;
    }
    int query(int now,int k)
    {
        int tmp=0;
        if(ch[now][0]) tmp=sum[ch[now][0]];
        if(k<=tmp) return query(ch[now][0],k);
        if(tmp+cnt[now]>=k) return key[now];
        return query(ch[now][1],k-tmp-cnt[now]);
    }
    int main()
    {
        freopen("cashier.in","r",stdin);
        freopen("cashier.out","w",stdout);
        scanf("%d%d",&n,&limit);
        char ch[1];int x;
        while(n--)
        {
            scanf("%s%d",ch,&x);
            switch(ch[0])
            {
                case 'I':
                    if(x<limit) continue;
                    insert(x-gather); break;
                case 'A':
                    gather+=x; break;
                case 'S':
                    gather-=x;
                    insert(limit-gather);
                    cut_lch();
                    cut();
                    break;
                case 'F':
                    if(x>sum[root]) printf("-1
    ");
                    else printf("%d
    ",query(root,sum[root]-x+1)+gather);
            }
        }
        printf("%d",leave);
    }
    View Code

    T2 反转卡片

    http://www.cnblogs.com/TheRoadToTheGold/p/6414979.html

    初做:2017.2.19  现在:2017.3.28

    3个小时

    这个题使splay中的节点编号与节点在序列中的顺序保持一致,然后splay的中序遍历就是卡片顺序。

    所以第i张卡片相当于splay中排名为i的节点,而且不需要在splay中存储权值,即卡片上的数字

    所以以前认为将卡片编号作为权值建splay是错误的

    #include<cstdio>
    #include<algorithm>
    #define N 300010
    using namespace std;
    int n,num[N],root;
    int fa[N],ch[N][2],sum[N];
    bool tag[N];
    void update(int x)
    {
        sum[x]=1+sum[ch[x][0]]+sum[ch[x][1]];
    }
    void build(int l,int r,int f)
    {
        if(l>r) return;
        int mid=l+r>>1;
        fa[mid]=f;sum[mid]=1;
        ch[f][mid>f]=mid;
        build(l,mid-1,mid);
        build(mid+1,r,mid);
        update(mid);
    }
    int getson(int x)
    {
        return ch[fa[x]][1]==x;
    }
    void rotate(int x,int & goal)
    {
        int y=fa[x],z=fa[y],kind=getson(x);
        if(y==goal) goal=x;
        else ch[z][ch[z][1]==y]=x;
        ch[y][kind]=ch[x][!kind]; fa[ch[y][kind]]=y;
        ch[x][!kind]=y; fa[y]=x;
        fa[x]=z;
        update(y);
    }
    void down(int x)
    {
        tag[x]^=1;
        if(ch[x][0]) tag[ch[x][0]]^=1;
        if(ch[x][1]) tag[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
    }
    void splay(int x,int & goal)
    {
        while(x!=goal)
        {
            if(tag[fa[fa[x]]]) down(fa[fa[x]]);
             if(tag[fa[x]]) down(fa[x]);
              if(tag[x]) down(x);
            int y=fa[x];
            if(y!=goal)
            {
                if(getson(y)==getson(x)) rotate(y,goal);
                else rotate(x,goal);
            }
            rotate(x,goal);    
        }
        update(x);
    }
    int find(int now,int x)
    {
        if(tag[now]) down(now);
        int tmp=0;
        if(ch[now][0]) tmp=sum[ch[now][0]];
        if(x<=tmp) return find(ch[now][0],x);
        if(tmp+1>=x) return now;
        return find(ch[now][1],x-tmp-1);
    }
    void rever(int l,int r)
    {
        int x=find(root,l-1),y=find(root,r+1);
        splay(x,root);splay(y,ch[x][1]);
        tag[ch[y][0]]^=1;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&num[i+1]);
        build(1,n+2,0);
        root=(n+3)/2;
        int maxn=100000,id,r,ans=0;
        while(maxn--)
        {
            id=find(root,2);
            r=num[id];
            if(r==1)
            {
                printf("%d",100000-maxn-1);
                return 0;
            }
            rever(2,r+1);
        }
        printf("-1");
    }
    View Code

    列举代码中好几个错误:

    ①、答案的输出

    if(r==1)
    {
        printf("%d",100000-maxn-1);
        return 0;
    }

    而不是  100000-maxn

    因为开头写的 while(maxn--)

    判断完maxn为true后,减1,输出里的maxn相对于while里已经减了1,所以应该是100000-(maxn+1)

    ②、rever函数中,打翻转标记应该是tag[ch[y][0]]^=1;

    而不是tag[ch[y][0]]=1

    ③、find函数里now和x混了,属于不过脑子的错误

    ④、splay里用了这个

    inline void splay(int x)
    {
        for(int fa;fa=f[x];rotate(x))
          if(f[fa]) rotate(getson(x)==getson(fa) ? fa:x);
        root=x;
        update(x);
    }

    上面的判断标准是f[fa]为true,因为根节点的父节点是0

    这个题是将点转到指定位置,所以判断标准是父节点是否是目标位置

    修改上面的代码改了好久就是不过

    所以,若是将点转到指定位置,干脆用这个

    void splay(int x,int & goal)
    {
        while(x!=goal)
        {
            if(tag[fa[fa[x]]]) down(fa[fa[x]]);
             if(tag[fa[x]]) down(fa[x]);
              if(tag[x]) down(x);
            int y=fa[x];
            if(y!=goal)
            {
                if(getson(y)==getson(x)) rotate(y,goal);
                else rotate(x,goal);
            }
            rotate(x,goal);    
        }
        update(x);
    }

    原来写的代码没有下传标记A了,很神奇

    ⑤、rotate 里

        if(y==goal) goal=x;
        else ch[z][ch[z][1]==y]=x;

    而不是

    if(z)ch[z][ch[z][1]==y]=x;

    ⑥、build里 update(mid)而不是update(f)

    还有一点:这里所有有关父节点与子节点的操作,都不需要判断是否有子节点

    why?

    T3  hdu 1890 Robotic Sort

    给出n的点,点有点权,i次操作

    每次操作 找到点权第i小的点是第j个,翻转第i个到第j个,输出j

    本题要输出k值在第几个位置

    很容易想到根据序列建立完全平衡二叉树,然后查k值的位置

    因为中序遍历就是序列,k值的位置就是k值的排名

    排名怎么查?

    以前写的都是递归,因为splay是依托权值大小关系建的,所以可以判断大小累计排名

    但这里不是,是根据序列位置建的

    我们无法判断点在点的左子树还是右子树

    所以弃疗了。。。。。。

    其实

    把点转到根节点,左子树大小+1就是排名

    做了一遍了,这里还想不到,果然还是弱。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 100010
    using namespace std;
    int n,root;
    int sum[N],ch[N][2],fa[N];
    bool tag[N];
    struct node
    {
        int h,id;
    }e[N];
    bool cmp(node p,node q)
    {
        if(p.h!=q.h) return p.h<q.h;
        return p.id<q.id;
    }
    void update(int x)
    {
        sum[x]=1;
        if(ch[x][0]) sum[x]+=sum[ch[x][0]];
        if(ch[x][1]) sum[x]+=sum[ch[x][1]];
    }
    void down(int x)
    {
        tag[x]^=1;
        if(ch[x][0]) tag[ch[x][0]]^=1;
        if(ch[x][1]) tag[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]); 
    }
    void build(int l,int r,int f)
    {
        if(l>r) return;
        int mid=l+r>>1;
        fa[mid]=f; ch[f][mid>f]=mid;
        sum[mid]=1;
        build(l,mid-1,mid);
        build(mid+1,r,mid);
        update(mid);
    }
    int find(int now,int x)//排名为x的是谁 
    {
        if(tag[now]) down(now);
        int tmp=0;
        if(ch[now][0]) tmp=sum[ch[now][0]];
        if(x<=tmp) return find(ch[now][0],x);
        if(tmp+1==x) return now;
        return find(ch[now][1],x-tmp-1);
    }
    void rotate(int x,int &goal)
    {
        int y=fa[x],z=fa[y];
        if(y==goal) goal=x;
        else ch[z][ch[z][1]==y]=x;
        int kind=ch[y][1]==x;
        ch[y][kind]=ch[x][!kind]; fa[ch[y][kind]]=y;
        ch[x][!kind]=y; fa[y]=x;
        fa[x]=z;
        update(y);
    }
    void splay(int x,int & goal)
    {
        while(x!=goal)
        {
            int y=fa[x],z=fa[y];
            if(tag[z]) down(z);
            if(tag[y]) down(y);
            if(tag[x]) down(x);
            if(y!=goal)
            {
                if(ch[y][1]==x^ch[z][1]==y) rotate(x,goal);
                else rotate(y,goal);
            }
            rotate(x,goal);    
        }
        update(x);
    }
    void rever(int l,int r)
    {
        int x=find(root,l-1),y=find(root,r+1);
        splay(x,root);splay(y,ch[root][1]);
        tag[ch[y][0]]^=1;
    }
    void clear()
    {
        memset(tag,0,sizeof(tag));
        memset(fa,0,sizeof(fa));
        memset(ch,0,sizeof(ch));
    }
    int main()
    {
        while(1)
        {
            scanf("%d",&n);
            if(!n) return 0;
            clear();
            for(int i=1;i<=n;i++) 
            {
                scanf("%d",&e[i].h);
                e[i].id=i;
            }
            sort(e+1,e+n+1,cmp);
            build(1,n+2,0);
            root=n+3>>1;
            int pos;
            for(int i=1;i<n;i++)
            {
                splay(e[i].id+1,root);
                pos=sum[ch[root][0]]+1;
                printf("%d ",pos-1);
                rever(i+1,pos);
            }
              printf("%d
    ",n);
        }
    }
    View Code
  • 相关阅读:
    scrapy中selenium的应用
    Django的锁和事务
    redis
    【leetcode】187. Repeated DNA Sequences
    【leetcode】688. Knight Probability in Chessboard
    【leetcode】576. Out of Boundary Paths
    【leetcode】947. Most Stones Removed with Same Row or Column
    【leetcode】948. Bag of Tokens
    【leetcode】946. Validate Stack Sequences
    【leetcode】945. Minimum Increment to Make Array Unique
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6635514.html
Copyright © 2011-2022 走看看