欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

P2617 Dynamic Rankings-动态主席树

程序员文章站 2024-03-02 21:59:04
...

题目描述

给定一个含有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继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。

对于每一个询问指令,你必须输出正确的回答。

输入输出格式

输入格式:

 

第一行有两个正整数n(1≤n≤100000),m(1≤m≤100000)。分别表示序列的长度和指令的个数。

第二行有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。

 

输出格式:

 

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

 

输入输出样例

输入样例#1:

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

输出样例#1:

3
6

说明

10%的数据中,m,n≤100;

20%的数据中,m,n≤1000;

50%的数据中,m,n≤10000。

对于所有数据,m,n≤100000

请注意常数优化,但写法正常的整体二分和树套树都可以以大约1000ms每个点的时间过。

来源:bzoj1901

本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。

 

题解:动态主席树查询区间第k小

#include<bits/stdc++.h>
#define begin b+1
#define end b+1+size
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int b[maxn+maxn];
int ca[maxn],cb[maxn],cc[maxn];
int xx[maxn],yy[maxn];
int size=0,cnt=0;
int root[maxn];
int t0,t1;
struct node{
    int l,r,sum;
}sz[maxn*400];//动态开 400倍 
void updata(int l,int r,int &x,int y,int v,int pos)//建树 
{
    if(x==0) x=++cnt;
    sz[x]=sz[y];
    sz[x].sum+=v;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(mid>=pos) updata(l,mid,sz[x].l,sz[y].l,v,pos);
    else updata(mid+1,r,sz[x].r,sz[y].r,v,pos); 
}
int getSum(int l,int r,int k)
{
    if(l==r) return l;
    int mid=(l+r)>>1,ans=0;
    for(int i=1;i<=t0;i++)	ans-=sz[sz[xx[i]].l].sum;
    for(int i=1;i<=t1;i++)	ans+=sz[sz[yy[i]].l].sum;
    if(ans>=k)
    {
        for(int i=1;i<=t0;i++) xx[i]=sz[xx[i]].l;
        for(int i=1;i<=t1;i++) yy[i]=sz[yy[i]].l;
        return getSum(l,mid,k);
    }
    else{
        for(int i=1;i<=t0;i++) xx[i]=sz[xx[i]].r;
        for(int i=1;i<=t1;i++) yy[i]=sz[yy[i]].r;
        return getSum(mid+1,r,k-ans);
    }
}
int low_bit(int x)
{
    return x&(-x);
}
int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[++size]=a[i];
    }
    for(int i=1;i<=m;i++)
    {
        char q[2];
        scanf("%s",q);
        if(q[0]=='Q')
        {
            scanf("%d %d %d",&ca[i],&cb[i],&cc[i]);
        }
        else 
        {
            scanf("%d %d",&ca[i],&cb[i]);
            b[++size]=cb[i];
        }
    }
    sort(b+1,b+1+size);//去重,离散化 
    size=unique(b+1,b+1+size)-b-1;
    for(int i=1;i<=n;i++)
    {
        int p=lower_bound(b+1,b+1+size,a[i])-b;//查询其位置 
        for(int j=i;j<=n;j+=low_bit(j))//树状数组维护 
        {
            updata(1,size,root[j],root[j],1,p);
        }
    }
    for(int i=1;i<=m;i++)
    {
        if(cc[i]==0)
        {
            int p=lower_bound(b+1,b+1+size,a[ca[i]])-b;
            for(int j=ca[i];j<=n;j+=low_bit(j))
            {
                updata(1,size,root[j],root[j],-1,p);
            }
            a[ca[i]]=cb[i];
            p=lower_bound(b+1,b+1+size,a[ca[i]])-b;
            for(int j=ca[i];j<=n;j+=low_bit(j))
            {
                updata(1,size,root[j],root[j],1,p);
            }
        }
        else
        {
            t0=0;
            t1=0;
            for(int j=ca[i]-1;j>0;j-=low_bit(j))
            {
                xx[++t0]=root[j];
            }
            for(int j=cb[i];j>0;j-=low_bit(j))
            {
                yy[++t1]=root[j];
            }
            printf("%d\n",b[getSum(1,size,cc[i])]);
        }
    }
}