• 伸展树复习


    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
  • 相关阅读:
    Json字串转换成Java复杂对象
    [Code Snipper]图片轮换
    将CSDN600W用户及密码帐号存入本地MySql数据库
    【转】一个隐形的java int溢出
    【转】展望未来,总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告
    如何在Android 4.0 ICS中禁用StatusBar | SystemBar | 状态栏 【完美版】
    【转】提问的智慧(How To Ask Questions the Smart)
    商业开发实战之VB篇精彩视频
    我的设计原语
    RAPIDXML 中文手册,根据官方文档完整翻译!
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6635514.html
Copyright © 2020-2023  润新知