• bzoj1901 Zju2112 Dynamic Rankings


    1901: Zju2112 Dynamic Rankings

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 8710  Solved: 3626
    [Submit][Status][Discuss]

    Description

    给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1
    ],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改
    变后的a继续回答上面的问题。

    Input

    第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。
    分别表示序列的长度和指令的个数。
    第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。
    接下来的m行描述每条指令
    每行的格式是下面两种格式中的一种。 
    Q i j k 或者 C i t 
    Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)
    表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。
    C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t
    m,n≤10000

    Output

     对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

    Sample Input

    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3

    Sample Output

    3
    6
    分析:带修改的主席树.
              其实主席树就是维护前缀和的权值线段树.单点修改,要O(n)的时间修改前缀和.这样承受不起,需要优化.树状数组就是一个log复杂度维护前缀和的数据结构,那么这道题就可以树状数组套主席树.
              主席树每个点表示的是什么要搞清楚.在这道题中,主席树上的每个点代表在树状数组里的点,那么每次修改一个数i都要不停地加lowbit,修改第i棵树.查询同理.
              这样的话有一个问题:第i棵线段树不能在以前的树的基础上建立,因为在这里每棵树代表的不再是前缀,而是点.
              考虑本题的修改操作,先将原数在树状数组中删除,接着在树状数组中加上新的数.查询操作像树状数组一样,将要查询的根给提出来.注意离散化,要将修改操作的值离散化!
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 20010;
    
    int n,m,a[maxn],b[maxn],cnt,tot,ansx[maxn],ansy[maxn],cnt1,cnt2,root[maxn];
    
    struct node
    {
        int x,y,z,id;
    }e[maxn];
    
    struct node2
    {
        int left,right,sum;
    }tr[2200011];
    
    void update(int l,int r,int &x,int y,int pos,int v)
    {
        x = ++tot;
        tr[x] = tr[y];
        tr[x].sum += v;
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        if (pos <= mid)
            update(l,mid,tr[x].left,tr[y].left,pos,v);
        else
            update(mid + 1,r,tr[x].right,tr[y].right,pos,v);
    }
    
    int query(int l,int r,int p)
    {
        if (l == r)
            return l;
        int mid = (l + r) >> 1;
        int res1 = 0,res2 = 0;
        for (int i = 1; i <= cnt1; i++)
            res1 += tr[tr[ansx[i]].left].sum;
        for (int i = 1; i <= cnt2; i++)
            res2 += tr[tr[ansy[i]].left].sum;
        if (p <= res2 - res1)
        {
            for (int j = 1; j <= cnt1; j++)
                ansx[j] = tr[ansx[j]].left;
            for (int j = 1; j <= cnt2; j++)
                ansy[j] = tr[ansy[j]].left;
            return query(l,mid,p);
        }
        else
        {
            for (int j = 1; j <= cnt1; j++)
                ansx[j] = tr[ansx[j]].right;
            for (int j = 1; j <= cnt2; j++)
                ansy[j] = tr[ansy[j]].right;
            return query(mid + 1,r,p - (res2 - res1));
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            b[i] = a[i];
        }
        cnt = n;
        for (int i = 1; i <= m; i++)
        {
            char ch[2];
            scanf("%s",ch);
            if (ch[0] == 'Q')
            {
                scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
                e[i].x--;
                e[i].id = 1;
            }
            else
            {
                scanf("%d%d",&e[i].x,&e[i].y);
                e[i].id = 2;
                b[++cnt] = e[i].y;
            }
        }
        sort(b + 1,b + 1 + cnt);
        cnt = unique(b + 1,b + 1 + cnt) - b - 1;
        for (int i = 1; i <= n; i++)
        {
            int temp = lower_bound(b + 1,b + 1 + cnt,a[i]) - b;
            for (int j = i; j <= n; j += j & (-j))
                update(1,cnt,root[j],root[j],temp,1);
        }
        for (int i = 1; i <= m; i++)
        {
            if (e[i].id == 1)
            {
                cnt1 = cnt2 = 0;
                for (int j = e[i].x;j; j -= j & (-j))
                    ansx[++cnt1] = root[j];
                for (int j = e[i].y;j; j -= j & (-j))
                    ansy[++cnt2] = root[j];
                printf("%d
    ",b[query(1,cnt,e[i].z)]);
            }
            else
            {
                int temp = lower_bound(b + 1,b + 1 + cnt,a[e[i].x]) - b;
                for (int j = e[i].x; j <= n; j += j & (-j))
                    update(1,cnt,root[j],root[j],temp,-1);
                a[e[i].x] = e[i].y;
                temp = lower_bound(b + 1,b + 1 + cnt,e[i].y) - b;
                for (int j = e[i].x; j <= n; j += j & (-j))
                    update(1,cnt,root[j],root[j],temp,1);
            }
        }
    
        return 0;
    }
  • 相关阅读:
    深入防火墙记录(2) java程序员
    今天装了Redhat Enterprise Linux 5.0 ,体验一下不同的感受. java程序员
    最小生成树
    UVA400 Unix ls
    sudt2404Super Prime
    sdut2143图结构练习——最短路径
    多校联赛(1)Saving Princess claire_
    树结构练习——排序二叉树的中序遍历
    hdu1042N!
    最短路径
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8280803.html
Copyright © 2020-2023  润新知