zoukankan      html  css  js  c++  java
  • ZOJ 2112 Dynamic Rankings

    ZOJ_2112

        当自己学了splay之后,这个题目的基本思想就可以理解了,但代码还是写得相当挫,在后面的学习过程中再不断完善吧。

        首先线段树可以完成对区间的限制,而平衡树则可以完成统计区间上不大于x的数,这样我们就可以在线段树的节点上放一棵平衡树,平衡树上有这个区间上所有的数。修改操作比较好完成,只要查找这个数在哪些区间中,并在对应的平衡树中更新相应的值即可。至于查询操作,我们可以先二分答案x,将问题转化成x是否可以作为第k大的数,然后只要统计区间中不大于x的数的数量n2,以及不大于x-1的数的数量n1,如果满足n1<k<=n2,那么自然x就是解了。

        由于线段树有logn层,每层的平衡树至多会使用n个节点,因为如果这个区间包含越界的元素,我们完全可以不建立这个平衡树,因为在访问区间的时候一定不会访问到这个区间,这样空间复杂度就是O(nlogn)。

    #include<stdio.h>
    #include<string.h>
    #define MAXD 50010
    #define MAXS 1000010
    #define INF 0x3f3f3f3f
    int N, Q, M, top, pool[MAXS], node, key[MAXS], left[MAXS], right[MAXS], size[MAXS], pre[MAXS], a[2 * MAXD], lx[4 * MAXD], rx[4 * MAXD];
    struct Splay
    {
    int T;
    void update(int x)
    {
    size[x] = size[left[x]] + size[right[x]] + 1;
    }
    void left_rotate(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)
    right[p] == x ? right[p] = y : left[p] = y;
    else
    T = y;
    update(x);
    }
    void right_rotate(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)
    right[p] == x ? right[p] = y : left[p] = y;
    else
    T = 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 ? left_rotate(y) : right_rotate(y);
    else
    {
    if(right[z] == y)
    {
    if(right[y] == x)
    left_rotate(z), left_rotate(y);
    else
    right_rotate(y), left_rotate(z);
    }
    else
    {
    if(left[y] == x)
    right_rotate(z), right_rotate(y);
    else
    left_rotate(y), right_rotate(z);
    }
    }
    }
    update(x);
    }
    int calculate(int &T, int k)
    {
    if(T == 0)
    return 0;
    if(k < key[T])
    return calculate(left[T], k);
    else
    return size[left[T]] + 1 + calculate(right[T], k);
    }
    int Delete(int &T, int v)
    {
    -- size[T];
    if(key[T] == v || (v < key[T] && left[T] == 0) || (v > key[T] && right[T] == 0))
    {
    int k = key[T], p = pre[T];
    if(left[T] == 0 || right[T] == 0)
    {
    pool[++ top] = T;
    T = left[T] + right[T];
    if(T)
    pre[T] = p;
    }
    else
    key[T] = Delete(left[T], key[T] + 1);
    return k;
    }
    if(v < key[T])
    return Delete(left[T], v);
    else
    return Delete(right[T], v);
    }
    int query(int k)
    {
    return calculate(left[right[T]], k);
    }
    void change(int k, int v)
    {
    Delete(T, k);
    splay(Insert(T, v, 0), right[T]);
    }
    void new_node(int &T, int v)
    {
    if(top)
    T = pool[top --];
    else
    T = ++ node;
    key[T] = v;
    size[T] = 1;
    left[T] = right[T] = 0;
    }
    int Insert(int &T, int v, int fa)
    {
    if(T == 0)
    {
    new_node(T, v);
    pre[T] = fa;
    return T;
    }
    ++ size[T];
    if(v < key[T])
    return Insert(left[T], v, T);
    else
    return Insert(right[T], v, T);
    }
    void init(int x, int y)
    {
    int i, j, k;
    T = 0;
    new_node(T, -INF), new_node(right[T], INF);
    pre[T] = 0, pre[right[T]] = T;
    size[T] = 2;
    for(i = x; i <= y; i ++)
    splay(Insert(T, a[i], 0), right[T]);
    }
    }sp[4 * MAXD];
    void init()
    {
    int i, j, k;
    for(M = 1; M < N + 2; M <<= 1);
    node = top = size[0] = left[0] = right[0] = 0;
    memset(a, 0, sizeof(a[0]) * M);
    for(i = 1; i <= N; i ++)
    scanf("%d", &a[i]);
    for(i = M; i < 2 * M; i ++)
    {
    lx[i] = rx[i] = i - M;
    if(lx[i] >= 1 && rx[i] <= N)
    sp[i].init(lx[i], rx[i]);
    }
    for(i = M - 1; i > 1; i --)
    {
    lx[i] = lx[2 * i], rx[i] = rx[2 * i + 1];
    if(lx[i] >= 1 && rx[i] <= N)
    sp[i].init(lx[i], rx[i]);
    }
    }
    void change(int x, int k)
    {
    int i;
    for(i = M + x; i ^ 1; i >>= 1)
    {
    if(lx[i] >= 1 && rx[i] <= N)
    sp[i].change(a[x], k);
    }
    a[x] = k;
    }
    void query(int x, int y, int k)
    {
    int i, j, min, max, mid, n1, n2;
    min = 0, max = INF;
    for(;;)
    {
    mid = (min + max) / 2;
    if(mid == min)
    break;
    n1 = n2 = 0;
    for(i = x + M - 1, j = y + M + 1; i ^ j ^ 1; i >>= 1, j >>= 1)
    {
    if(~i & 1)
    {
    n1 += sp[i ^ 1].query(mid - 1), n2 += sp[i ^ 1].query(mid);
    }
    if(j & 1)
    n1 += sp[j ^ 1].query(mid - 1), n2 += sp[j ^ 1].query(mid);
    }
    if(n1 >= k)
    max = mid;
    else
    min = mid;
    }
    printf("%d\n", mid);
    }
    void solve()
    {
    int i, j, k, x, y;
    char b[5];
    for(i = 0; i < Q; i ++)
    {
    scanf("%s", b);
    if(b[0] == 'Q')
    {
    scanf("%d%d%d", &x, &y, &k);
    query(x, y, k);
    }
    else
    {
    scanf("%d%d", &x, &k);
    change(x, k);
    }
    }
    }
    int main()
    {
    int t;
    scanf("%d", &t);
    while(t --)
    {
    scanf("%d%d", &N, &Q);
    init();
    solve();
    }
    return 0;
    }


  • 相关阅读:
    指向行数组指针和指针数组的区别
    安装文件在icinga上安装check_mk
    模式浏览器火狐、谷歌、IE关于document.body.scrollTop和document.documentElement.scrollTop 以及值为0的问题
    执行对象java面试题目2013/5/16
    属性序列化gson的@Expose注解和@SerializedName注解
    语言编译器编程语言分类及入门
    按钮实现Python绘图工具matplotlib的使用
    实现注册表网页超链接调用应用程序实现
    服务方法android如何保证service不被杀死
    函数日期mysql获取当天日期
  • 原文地址:https://www.cnblogs.com/staginner/p/2411993.html
Copyright © 2011-2022 走看看