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\n",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;
}

 

posted @ 2018-01-13 22:54  zbtrs  阅读(...)  评论(...编辑  收藏