zoukankan      html  css  js  c++  java
  • POJ 2104 Kth Number

     POJ_2104

        上课之前大概看了一下划分树,后来上课的时候自己YY了一个“划分树”,结果发现每次查询复杂度不是logn的,大约是logn*logn的,写出来之后一交好像跟归并树的复杂度差不多,也就这个就是归并树吧……

        今天不早了,就先睡了,等明天起来之后再仔细研究一下划分树怎么写吧。

    View Code
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define MAXD 400010
    #define MAXM 2000010
    int N, M, a[MAXD], x[MAXM], p, left[MAXD], right[MAXD], lx[MAXD], rx[MAXD], e;
    int cmpr(const void *_p, const void *_q)
    {
    int *p = (int *)_p, *q = (int *)_q;
    if(a[*p] == a[*q])
    return *p - *q;
    return a[*p] - a[*q];
    }
    int cmp(const void *_p, const void *_q)
    {
    int *p = (int *)_p, *q = (int *)_q;
    return *p - *q;
    }
    void init()
    {
    int i;
    for(i = 1; i <= N; i ++)
    {
    scanf("%d", &a[i]);
    x[i] = i;
    }
    }
    void add(int l, int r)
    {
    int i;
    ++ e;
    left[e] = right[e] = -1;
    lx[e] = p, rx[e] = p + r - l;
    for(i = l; i <= r; i ++)
    x[p ++] = x[i];
    }
    void build(int cur)
    {
    int l, r, m;
    l = lx[cur], r = rx[cur];
    if(l != r)
    {
    m = (l + r) / 2;
    add(l, m), left[cur] = e;
    build(left[cur]);
    if(m < r)
    {
    add(m + 1, r), right[cur] = e;
    build(right[cur]);
    }
    qsort(&x[l], r - l + 1, sizeof(x[0]), cmp);
    }
    }
    int search(int l, int r, int k, int cur)
    {
    if(left[cur] == -1)
    return a[x[lx[cur]]];
    int i, j, p, n, min, mid, max;
    p = left[cur];
    if(x[rx[p]] < l || x[lx[p]] > r)
    n = 0;
    else
    {
    min = lx[p], max = rx[p] + 1;
    for(;;)
    {
    mid = (min + max) / 2;
    if(mid == min)
    break;
    if(x[mid] < l)
    min = mid;
    else
    max = mid;
    }
    j = x[mid] < l ? max : mid;
    min = lx[p], max = rx[p] + 1;
    for(;;)
    {
    mid = (min + max) / 2;
    if(mid == min)
    break;
    if(x[mid] <= r)
    min = mid;
    else
    max = mid;
    }
    n = max - j;
    }
    if(n >= k)
    return search(l, r, k, left[cur]);
    else
    return search(l, r, k - n, right[cur]);
    }
    void solve()
    {
    int i, j, k, l, r;
    e = 0;
    left[e] = right[e] = -1;
    lx[e] = 1, rx[e] = N;
    qsort(&x[1], N, sizeof(x[0]), cmpr);
    p = N + 1;
    build(0);
    for(i = 0; i < M; i ++)
    {
    scanf("%d%d%d", &l, &r, &k);
    printf("%d\n", search(l, r, k, 0));
    }
    }
    int main()
    {
    while(scanf("%d%d", &N, &M) == 2)
    {
    init();
    solve();
    }
    return 0;
    }

        上完体育课后仔细学了一下这个博客(http://blog.csdn.net/jasonzhu8/article/details/5833339)里面划分树的写法,发现实际上我昨天YY的那个已经很像划分树了,只不过在建树和查找的时候做得过于繁琐了。这个博客里里面划分树上并没有存实际的元素,也没有存元素的标号,而是存的该元素在原序列中的rank,这样能够在建树的过程中能够很方便地统计出每个节点第i个元素及之前有多少元素划分到了左子树中,原因就在于每个节点上各元素的rank一定会组成一个连续的区间,而且区间的范围就等于数组下标的范围,这样只要通过将区间的中点mid找到,rank小于或等于mid的元素就会被划到左子树中。

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define MAXK 20
    #define MAXD 100010
    int N, M, sa[MAXD], rank[MAXK][MAXD], sum[MAXK][MAXD], a[MAXD];
    int cmp(const void *_p, const void *_q)
    {
    int *p = (int *)_p, *q = (int *)_q;
    if(a[*p] == a[*q])
    return *p - *q;
    return a[*p] - a[*q];
    }
    void init()
    {
    int i, j, k;
    for(i = 1; i <= N; i ++)
    {
    scanf("%d", &a[i]);
    sa[i] = i;
    }
    }
    void build(int lx, int rx, int d)
    {
    if(lx == rx)
    return ;
    int i, j, k, mid = (lx + rx) / 2, p = 0;
    for(i = lx; i <= rx; i ++)
    {
    if(rank[d][i] <= mid)
    {
    rank[d + 1][lx + p] = rank[d][i];
    ++ p;
    }
    else
    rank[d + 1][mid + i - lx + 1 - p] = rank[d][i];
    sum[d][i] = p;
    }
    build(lx, mid, d + 1);
    build(mid + 1, rx, d + 1);
    }
    int search(int lx, int rx, int x, int y, int k, int d)
    {
    if(lx == rx)
    return a[sa[rank[d][lx]]];
    int n, m, mid = (lx + rx) / 2;
    n = sum[d][y], m = (x == lx ? 0 : sum[d][x - 1]);
    if(n - m >= k)
    return search(lx, mid, lx + m, lx + n - 1, k, d + 1);
    else
    return search(mid + 1, rx, mid + 1 + x - lx - m, mid + 1 + y - lx - n, k - n + m, d + 1);
    }
    void solve()
    {
    int i, j, k, x, y;
    qsort(sa + 1, N, sizeof(sa[0]), cmp);
    for(i = 1; i <= N; i ++)
    rank[0][sa[i]] = i;
    build(1, N, 0);
    for(i = 0; i < M; i ++)
    {
    scanf("%d%d%d", &x, &y, &k);
    printf("%d\n", search(1, N, x, y, k, 0));
    }
    }
    int main()
    {
    while(scanf("%d%d", &N, &M) == 2)
    {
    init();
    solve();
    }
    return 0;
    }



  • 相关阅读:
    Response.Status http协议状态代码
    ASP.NET MVC 如何实现头压缩
    Google PR值原理和详细解说
    NodeJS 深入浅出
    C#: ToString格式
    HttpHandler实现媒体文件和图像文件的盗链(防盗链设计)
    ASP.NET MVC 使用Areas功能的常见错误
    VC中利用多线程技术实现线程之间的通信
    基于Visual C++的Winsock API研究
    键盘钩子程序
  • 原文地址:https://www.cnblogs.com/staginner/p/2395257.html
Copyright © 2011-2022 走看看