Evanyou Blog 彩带

P2617 Dynamic Rankings

题目描述

给定一个含有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≤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。

输出格式:

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

输入输出样例

输入样例#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分钟完成数据制作。

 

Solution:

  本题带修改主席树板子题

  原题数据用分快或者线段树套平衡树可过,加强版的话貌似只能整体二分或者带修改主席树了。

  说下带修改主席树,其实很简单。

  主席树可以理解为前缀式线段树,而对于前缀和上的修改,维护利器就是树状数组啦。  

  我们在普通主席树建树的基础上,对i节点的建树,改为对Bit上包含该节点的每个位置都构建主席树。

  那么单点修改时直接先去掉该节点,改完值后再插入树中 ; 而区间查询第k大的值,直接取出Bit维护的$r,l-1$的各个前缀主席树相减,得到该段区间上的分布情况,然后普通主席树的第k大值查询就好了。

代码:

 

/*Code by 520 -- 9.19*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
#define lowbit(x) (x&-x)
using namespace std;
const int N=100005;
int n,m,rt[N],cnt,tot,*Q[N<<1],val[N];
int a[N],qa[N],qb[N],qc[N],qd[N],X[N],Y[N],tx,ty;
struct node{
    int ls,rs,siz;
}t[N*600];
char s[10];

int gi(){
    int a=0;char x=getchar();bool f=0;
    while((x<'0'||x>'9')&&x!='-') x=getchar();
    if(x=='-') x=getchar(),f=1;
    while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return f?-a:a;
}

il bool cmp(const int *a,const int *b){return *a<*b;}

void ins(int l,int r,int k,int x,int lst,int &rt){
    if(!rt) rt=++tot; t[rt]=t[lst],t[rt].siz+=x;
    if(l==r) return;
    int m=l+r>>1;
    if(k<=m) ins(l,m,k,x,t[lst].ls,t[rt].ls);
    else ins(m+1,r,k,x,t[lst].rs,t[rt].rs);
}

il void update(int i,int v){
    int k=a[i];
    while(i<=n) ins(1,cnt,k,v,rt[i],rt[i]),i+=lowbit(i);
}

int query(int x){
    int l=1,r=cnt,k=qc[x];
    tx=ty=0;
    for(RE int i=qa[x]-1;i;i-=lowbit(i)) X[++tx]=rt[i];
    for(RE int i=qb[x];i;i-=lowbit(i)) Y[++ty]=rt[i];
    while(l<r){
        int m=l+r>>1,res=0;
        For(i,1,tx) res-=t[t[X[i]].ls].siz;
        For(i,1,ty) res+=t[t[Y[i]].ls].siz;
        if(k<=res) {
            For(i,1,tx) X[i]=t[X[i]].ls;
            For(i,1,ty) Y[i]=t[Y[i]].ls;
            r=m;
        }
        else {
            For(i,1,tx) X[i]=t[X[i]].rs;
            For(i,1,ty) Y[i]=t[Y[i]].rs;
            l=m+1,k-=res;
        }
    }
    return l;
}

int main(){
    n=gi(),m=gi();
    For(i,1,n) a[i]=gi(),Q[++tot]=&a[i];
    For(i,1,m) {
        scanf("%s",s),qa[i]=gi(),qb[i]=gi();
        if(s[0]=='Q') qc[i]=gi(); else Q[++tot]=&qb[i];
    }
    sort(Q+1,Q+tot+1,cmp);
    int lst=-1;
    For(i,1,tot) if(*Q[i]!=lst) lst=*Q[i],*Q[i]=++cnt,val[cnt]=lst; else *Q[i]=cnt;
    memset(&t[tot=0],0,sizeof(t[tot]));
    For(i,1,n) update(i,1);
    For(i,1,m) 
        if(qc[i]) printf("%d\n",val[query(i)]);
        else update(qa[i],-1),a[qa[i]]=qb[i],update(qa[i],1);
    return 0;
}

 

 

 

 

posted @ 2018-09-20 09:17  five20  阅读(176)  评论(0编辑  收藏  举报
Live2D