zoukankan      html  css  js  c++  java
  • HDU 1890 Robotic Sort

    HDU_1890

        第一次写涉及到区间翻转的splay,结果就没注意到翻转的操作类似于线段树中对区间0、1取反的操作,下传标记的时候记录翻转的标记rev应该是加1模2,而不能简单地将左右儿子的rev置为1。

        下面说说具体的思路吧。

        我们每次可以先将“最小”的点旋转到根,那么根左边的区间自然就是要翻转的区间了,于是我们对根左边的区间打上翻转的标记,然后将根删除,如此反复N-1遍。对于每次要输出的值,假设我们现在试图令第i个block到位,那么把这个点旋转到根后,输出i+size[left[T]]即可,其中T表示根。当然,最后还要输出一个N。

        然而,我们要如何知道每次该旋转哪个block呢?即便我们知道该旋转哪个block,那这个block在splay中又处于哪个位置呢?对于第一个问题,我们可以先将block排个序,这样自然就知道每次该旋转哪个block了。对于第二个问题,我们可以在建树的过程中把每个block所在的节点的标号存下来即可。这样我们每次就可以很方便的知道该旋转哪个block了,同时也能方便地知道它在splay中的位置,但是这时我们不能直接调用splay操作把这个点旋转上去,因为这个节点的上方有可能还有一些翻转的标记没有下传,因此我们要先从这个节点开始向上找到根,并在找的过程中记录一下路径,然后再从根节点向下沿记录好的路径去找要旋转的节点,并在找的过程中下传翻转标记。

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define MAXD 100010
    int N, node, T, height[MAXD], size[MAXD], pre[MAXD], left[MAXD], right[MAXD], rev[MAXD], P[MAXD];
    struct Block
    {
    int key, cur;
    }block[MAXD];
    int cmp(const void *_p, const void *_q)
    {
    Block *p = (Block *)_p, *q = (Block *)_q;
    if(height[p->key] == height[q->key])
    return p->key - q->key;
    return height[p->key] < height[q->key] ? -1 : 1;
    }
    void newnode(int &cur, int k)
    {
    cur = ++ node;
    block[k].key = k, block[k].cur = cur;
    left[cur] = right[cur] = 0;
    rev[cur] = 0;
    }
    void update(int cur)
    {
    size[cur] = size[left[cur]] + size[right[cur]] + 1;
    }
    void pushdown(int cur)
    {
    if(rev[cur])
    {
    int ls = left[cur], rs = right[cur];
    rev[ls] = (rev[ls] + 1) % 2, rev[rs] = (rev[rs] + 1) % 2;
    left[cur] = rs, right[cur] = ls;
    rev[cur] = 0;
    }
    }
    void build(int &cur, int x, int y, int p)
    {
    int mid = (x + y) / 2;
    newnode(cur, mid);
    size[cur] = y - x + 1;
    pre[cur] = p;
    if(x == y)
    return ;
    if(x < mid)
    build(left[cur], x, mid - 1, cur);
    if(mid < y)
    build(right[cur], mid + 1, y, cur);
    }
    void init()
    {
    int i;
    T = node = left[0] = right[0] = size[0] = 0;
    for(i = 1; i <= N; i ++)
    scanf("%d", &height[i]);
    build(T, 1, N, 0);
    }
    void leftrotate(int x)
    {
    int y = right[x], p = pre[x];
    right[x] = left[y];
    if(right[x])
    pre[right[x]] = x;
    left[y] = x;
    pre[x] = y;
    pre[y] = p;
    if(p == 0)
    T = y;
    else
    right[p] == x ? right[p] = y : left[p] = y;
    update(x);
    }
    void rightrotate(int x)
    {
    int y = left[x], p = pre[x];
    left[x] = right[y];
    if(left[x])
    pre[left[x]] = x;
    right[y] = x;
    pre[x] = y;
    pre[y] = p;
    if(p == 0)
    T = y;
    else
    right[p] == x ? right[p] = y : left[p] = y;
    update(x);
    }
    void splay(int x, int goal)
    {
    int y, z;
    for(;;)
    {
    if((y = pre[x]) == goal)
    break;
    if((z = pre[y]) == goal)
    right[y] == x ? leftrotate(y) : rightrotate(y);
    else
    {
    if(right[z] == y)
    {
    if(right[y] == x)
    leftrotate(z), leftrotate(y);
    else
    rightrotate(y), leftrotate(z);
    }
    else
    {
    if(left[y] == x)
    rightrotate(z), rightrotate(y);
    else
    leftrotate(y), rightrotate(z);
    }
    }
    }
    update(x);
    }
    void rotateto(int x)
    {
    int i;
    for(i = x; i != T; i = pre[i])
    P[pre[i]] = i;
    for(i = T;;)
    {
    pushdown(i);
    if(i == x)
    break;
    i = right[i] == P[i] ? right[i] : left[i];
    }
    splay(x, 0);
    }
    int Delete(int &x)
    {
    int k;
    pushdown(x);
    -- size[x];
    if(x == T || right[x] == 0)
    {
    if(right[x] == 0)
    {
    k = x;
    if(left[x])
    pre[left[x]] = pre[x];
    x = left[x];
    }
    else
    {
    k = Delete(left[x]);
    left[k] = left[T], right[k] = right[T];
    if(left[k])
    pre[left[k]] = k;
    if(right[k])
    pre[right[k]] = k;
    T = k;
    pre[T] = 0;
    update(T);
    }
    return k;
    }
    else
    return Delete(right[x]);
    }
    void Remove()
    {
    int i, p;
    rev[left[T]] = (rev[left[T]] + 1) % 2;
    if(left[T] == 0 || right[T] == 0)
    {
    T = left[T] + right[T];
    pre[T] = 0;
    }
    else
    Delete(T);
    }
    void solve()
    {
    int i;
    qsort(block + 1, N, sizeof(block[0]), cmp);
    for(i = 1; i < N; i ++)
    {
    rotateto(block[i].cur);
    printf("%d ", i + size[left[T]]);
    Remove();
    }
    printf("%d\n", N);
    }
    int main()
    {
    for(;;)
    {
    scanf("%d", &N);
    if(!N)
    break;
    init();
    solve();
    }
    return 0;
    }


  • 相关阅读:
    Codeforces 938G(cdq分治+可撤销并查集+线性基)
    codeforces 938F(dp+高维前缀和)
    寒武纪camp Day6
    寒武纪camp Day5
    寒武纪camp Day4
    bzoj4161 (k^2logn求线性递推式)
    loj10003加工生产调度
    loj10002喷水装置
    loj10001种树
    bzoj1023
  • 原文地址:https://www.cnblogs.com/staginner/p/2427883.html
Copyright © 2011-2022 走看看