zoukankan      html  css  js  c++  java
  • HDU 3436 Queuejumpers

    HDU_3436

        这个题目无论用什么方法做,首先离散化时候一定要处理好,否则后面会越想越乱。一个比较好的离散化的思路就是把需要Top和Query点看成一个小区间,然后把这些点之间的部分,以及头尾两个部分看成其他的一个一个的区间。

        线段树或者树状数组的做法可以参考http://www.cppblog.com/Yuan/archive/2010/08/18/123871.html,我就只说一下用splay的思路吧。

    维护splay只需要维护一个size,但这个size表示的不是子树的节点数,而是子树上的所有区间所包含的点的总数。

        对于top操作,由于我们要先找到那个点(或者说是小区间)的节点标号(每个区间对应的splay上的节点标号可以在建树的时候处理出来,查找节点标号的时候由于离散化后区间是有序存储的,所以可以对存区间的数组二分查找来找到这个小区间),然后将这个点旋转根后删除,再重新插入这个点。

        对于Query操作,我们只需要把这个点旋转到根,然后输出size[left[T]]+1即可。

        对于Rank操作,我们可以从上到下查找,直到确定某个区间包含这个位置时再将其计算出来即可。

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define MAXD 100010
    int N, Q, T, node, tx[MAXD], begin[MAXD], end[MAXD], nodep[MAXD];
    int num[2 * MAXD], size[2 * MAXD], left[2 * MAXD], right[2 * MAXD], pre[2 * MAXD], key[2 * MAXD];
    char b[MAXD][10];
    int ob[MAXD];
    int cmp(const void *_p, const void *_q)
    {
    int *p = (int *)_p, *q = (int *)_q;
    return *p - *q;
    }
    void update(int cur)
    {
    size[cur] = size[left[cur]] + size[right[cur]] + num[cur];
    }
    void newnode(int &cur, int k)
    {
    cur = ++ node;
    size[cur] = num[cur] = end[k] - begin[k] + 1;
    key[cur] = k;
    nodep[k] = cur;
    left[cur] = right[cur] = 0;
    }
    void build(int &cur, int x, int y, int p)
    {
    int mid = (x + y) / 2;
    newnode(cur, mid);
    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);
    update(cur);
    }
    void init()
    {
    int i, j, k;
    scanf("%d%d", &N, &Q);
    k = 0;
    tx[k ++] = 0;
    for(i = 0; i < Q; i ++)
    {
    scanf("%s%d", b[i], &ob[i]);
    if(b[i][0] == 'T' || b[i][0] == 'Q')
    tx[k ++] = ob[i];
    }
    tx[k ++] = N;
    qsort(tx, k, sizeof(tx[0]), cmp);
    N = 0;
    for(i = 1; i < k; i ++)
    if(tx[i] != tx[i - 1])
    {
    if(tx[i] - tx[i - 1] > 1)
    {
    begin[N] = tx[i - 1] + 1, end[N] = tx[i] - 1;
    ++ N;
    }
    begin[N] = end[N] = tx[i];
    ++ N;
    }
    T = node = left[0] = right[0] = size[0] = num[0] = 0;
    build(T, 0, N - 1, 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);
    }
    int BS(int x)
    {
    int max, mid, min;
    min = 0, max = N;
    for(;;)
    {
    mid = (max + min) / 2;
    if(mid == min)
    break;
    if(begin[mid] <= x)
    min = mid;
    else
    max = mid;
    }
    return mid;
    }
    int Delete(int &cur, int p)
    {
    int k;
    if(cur == T || right[cur] == 0)
    {
    if(cur == T)
    {
    k = Delete(left[cur], cur);
    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);
    }
    else
    {
    k = cur;
    if(left[k])
    pre[left[k]] = p;
    cur = left[k];
    }
    return k;
    }
    else
    {
    k = Delete(right[cur], cur);
    update(cur);
    return k;
    }
    }
    void Insert(int &cur, int k, int p)
    {
    if(cur == 0)
    {
    newnode(cur, k);
    pre[cur] = p;
    return ;
    }
    Insert(left[cur], k, cur);
    update(cur);
    }
    void Top(int x)
    {
    int k, cur;
    k = BS(x);
    cur = nodep[k];
    splay(cur, 0);
    if(left[T] == 0 || right[T] == 0)
    {
    T = left[T] + right[T];
    pre[T] = 0;
    }
    else
    Delete(T, 0);
    Insert(T, k, 0);
    splay(node, 0);
    }
    void Query(int x)
    {
    int k, cur;
    k = BS(x);
    cur = nodep[k];
    splay(cur, 0);
    printf("%d\n", size[left[cur]] + 1);
    }
    int Search(int cur, int x)
    {
    int ls = left[cur], rs = right[cur], k = key[cur];
    if(x <= size[ls])
    return Search(left[cur], x);
    else if(x <= size[ls] + num[cur])
    return begin[k] + (x - size[ls]) - 1;
    else
    return Search(right[cur], x - size[ls] - num[cur]);
    }
    void Rank(int x)
    {
    printf("%d\n", Search(T, x));
    }
    void solve()
    {
    int i, j, k;
    for(i = 0; i < Q; i ++)
    {
    if(b[i][0] == 'T')
    Top(ob[i]);
    else if(b[i][0] == 'Q')
    Query(ob[i]);
    else
    Rank(ob[i]);
    }
    }
    int main()
    {
    int t, tt;
    scanf("%d", &t);
    for(tt = 0; tt < t; tt ++)
    {
    init();
    printf("Case %d:\n", tt + 1);
    solve();
    }
    return 0;
    }


  • 相关阅读:
    使用EntityFramework之Code First开发与MySql数据库问题一例
    使用Emit创建DBContext对象
    一个实用的Metro滚屏效果示例
    合理使用EntityFramework数据验证的异常错误提示信息
    Metro app中使用内存流压缩和解压
    64位的windows操作系统上运行32位asp.net web应用程序的时候,出现试图加载格式不正确的程序的解决方法
    VSTO中自定义XML功能区实现Ribbon控件互相更新
    基于任务并行库实现多线程下载示例
    Android系统刷机成功后网络信号显示“无服务”修正
    Solution Explorer中显示依赖文件和链接文件
  • 原文地址:https://www.cnblogs.com/staginner/p/2429080.html
Copyright © 2011-2022 走看看