[bzoj1901]Zju2112 Dynamic Rankings

给定数组,单点修改,区间查询k小。$(n \leq 10000)$

暴力题?挺暴力的。树状数组+动态开点线段树。

树状数组维护每个权值的前缀和。可以视为是树状数组的每个节点开一个主席树吧。

修改:修改树状数组上包含修改点的权值线段树。$O(\log^2n)$

查询:像主席树一样不断通过二分缩小区间,区间和变成用树状数组求。由于每次二分要查询的节点是一样的,需要维护这些节点的pointer跳到哪里。$O(\log^2n)$话说我没维护这个是$O(\log^3n)$的。。。Sinogi大佬写了!%%%比我快(长)很多!

但是这种题n都10000了随便怎么做了吧,,,暴力貌似可过,,,尬

#include<bits/stdc++.h>
using namespace std;
const int N=20010;
inline int read(){
    int r=0,c=getchar();
    while(!isdigit(c))c=getchar();
    while(isdigit(c))
    r=r*10+c-'0',c=getchar();
    return r;
}
struct Node{
    int ls,rs,sum;
}T[N*100];
struct ask{
    int opt,l,r,k;
}q[N];
int rt[N],n,m,cnt;
int a[N],b[N],tot,v;
void upd(int &k,int l,int r,int val){
    if(!k)k=++cnt;
    T[k].sum+=v;
    if(l==r){
        return;
    }
    int mid=l+r>>1;
    if(val<=mid)upd(T[k].ls,l,mid,val);
    else upd(T[k].rs,mid+1,r,val);
}
void modify(int x,int w){
    w=lower_bound(b+1,b+tot+1,w)-b;
    for(int i=x;i<=n;i+=i&-i)
    upd(rt[i],1,tot,w);
}
int pt[N],L,R;
int sum(int x,int l,int r){
    if(!x)return 0;
    if(L<=l&&r<=R){
        return T[x].sum;
    }
    int mid=l+r>>1,ans=0;
    if(L<=mid)ans+=sum(T[x].ls,l,mid);
    if(R>mid) ans+=sum(T[x].rs,mid+1,r);
    return ans;
}
int query(int l,int r){
    int ret=0;
    for(int i=r;i;i-=i&-i)
    ret+=sum(rt[i],1,tot);
    for(int i=l;i;i-=i&-i)
    ret-=sum(rt[i],1,tot);
    return ret;
}
void init(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    a[i]=read(),b[++tot]=a[i];
    char s[5];
    for(int i=1;i<=m;i++){
        scanf("%s",s);
        if(s[0]=='C'){
            int x=read(),w=read();
            q[i]=(ask){0,x,x,w};
            b[++tot]=w;
        }
        else{
            int l=read(),r=read(),w=read();
            q[i]=(ask){1,l,r,w};
            b[++tot]=w;
        }
    }
    sort(b+1,b+tot+1);
    tot=unique(b+1,b+tot+1)-b-1;
}
void solve(){
    for(int i=1;i<=n;i++)
    v=1,modify(i,a[i]);
    for(int i=1;i<=m;i++){
        if(!q[i].opt){
            int x=q[i].l;
            v=-1;modify(x,a[x]);
            v=1;modify(x,a[x]=q[i].k);
        }
        else{
            int x=q[i].l-1,y=q[i].r,rk=q[i].k;
            int l=1,r=tot;
            while(l^r){
                int mid=l+r>>1;
                L=l,R=mid;
                int t=query(x,y);
                if(rk<=t)r=mid;
                else l=mid+1,rk-=t;
            }
            printf("%d\n",b[l]);
        }
    }
}
int main(){
    init();
    solve();
}

 

posted @ 2017-12-25 20:12  orzzz  阅读(...)  评论(...编辑  收藏