zoukankan      html  css  js  c++  java
  • 可修改的区间第K大 BZOJ1901 ZOJ2112

    http://blog.csdn.net/u014492306/article/details/47981315   //变相离线做法

    离散化缩小区间范围,做两大个线段树,第一个就是普通的持久化树,有个前缀和就好。

    第二个用线段树套树状数组,每次询问就把这两个都求出来加一下。

    更改就更改第二个,其实更改的时候只需要建一条链然后重复用这条链衍生就好了,但是为了抄的方便,就不改了。。。

    当然这个空间上比较优秀的只有O(nlogn).

    #include<bits/stdc++.h>
    #define lowbit(x) (x&(-x))
    using namespace std;
    const int N=6e4+5;
    const int M=2600006;
    int m,n,nn,tot;
    int a[N],f[N],T[N],S[N];
    int sum[M],l[M],r[M];
    int use[N];
    int h(int x) {return lower_bound(f+1,f+nn+1,x)-f;}
    void update(int pr,int lx,int rx,int v,int k){
        l[++tot]=l[pr],r[tot]=r[pr],sum[tot]=sum[pr]+k;
        if(lx==rx) return;
        int mid=(lx+rx)>>1;
        if(v<=mid) l[tot]=tot+1,update(l[pr],lx,mid,v,k);
        else r[tot]=tot+1,update(r[pr],mid+1,rx,v,k);
    }
    int Sum(int x){
        int res=0;
        for(int i=x;i;i-=lowbit(i)) res+=sum[l[use[i]]];
        return res;
    }
    void add(int x,int v,int k){
        int temp;
        for(int i=x;i<=n;i+=lowbit(i)) {
            temp=S[i];
            S[i]=tot+1;
            update(temp,1,nn,v,k);
        }
    }
    int query(int L,int R,int k){
        for(int i=L-1;i;i-=lowbit(i)) use[i]=S[i];
        for(int i=R;i;i-=lowbit(i)) use[i]=S[i];
        int lx=1,rx=nn,lt=T[L-1],rt=T[R];
        while(lx<rx) {
            int mid=(lx+rx)>>1;
            int tmp=Sum(R)-Sum(L-1)+sum[l[rt]]-sum[l[lt]];
            if(k<=tmp) {
                rx=mid;
                for(int i=L-1;i;i-=lowbit(i)) use[i]=l[use[i]];
                for(int i=R;i;i-=lowbit(i)) use[i]=l[use[i]];
                lt=l[lt],rt=l[rt];
            }
            else {
                lx=mid+1,k-=tmp;
                for(int i=L-1;i;i-=lowbit(i)) use[i]=r[use[i]];
                for(int i=R;i;i-=lowbit(i)) use[i]=r[use[i]];
                lt=r[lt],rt=r[rt];
            }
        }
        return f[lx];
    }
    char op[5];
    int q[10005][4],Ta;
    int main(){
        for(scanf("%d",&Ta);Ta--;) {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i) scanf("%d",a+i),f[i]=a[i];
            nn=n;
            for(int i=1;i<=m;++i) {
                scanf("%s",op);
                if(op[0]=='Q') {
                    scanf("%d%d%d",&q[i][1],&q[i][2],&q[i][3]);
                    q[i][0]=1;
                }
                else {
                    scanf("%d%d",&q[i][1],&q[i][2]);
                    q[i][0]=0;
                    f[++nn]=q[i][2];
                }
            }
            sort(f+1,f+1+nn);
            nn=unique(f+1,f+nn+1)-f-1;
            tot=0,T[0]=0;
            for(int i=1;i<=n;++i) T[i]=tot+1,update(T[i-1],1,nn,h(a[i]),1);
            for(int i=1;i<=n;++i) S[i]=0;
            for(int i=1;i<=m;++i) {
                if(q[i][0]) printf("%d
    ",query(q[i][1],q[i][2],q[i][3]));
                else {
                    add(q[i][1],h(a[q[i][1]]),-1);
                    add(q[i][1],h(q[i][2]),1);
                    a[q[i][1]]=q[i][2];
                }
            }
        }
        return 0;
    }

    如果强制在线的话,只能一开始就用线段树套树状数组了,空间复杂度O(nlog(1e9)log(1e9)),为什么是1e9是因为你没办法事先离散化,因为你不知道更改的时候他要改成什。

    http://blog.sina.com.cn/s/blog_4a0c4e5d0101c3yj.html

  • 相关阅读:
    eclipse注释模板__自动生成方法注释
    java HashMap--统计其中有相同value的key的个数
    java synchronized 详解
    进程间通信-共享内存
    辅导-计算机编程方面
    gnu make
    适应c++ 新特性
    tomcat服务器
    springmvc笔记
    Idea使用SVN教程
  • 原文地址:https://www.cnblogs.com/mfys/p/8184926.html
Copyright © 2011-2022 走看看