zoukankan      html  css  js  c++  java
  • 「Ynoi2018」未来日记

    「Ynoi2018」未来日记

    区间x->y,kth值...

    不管了,先序列分块...

    查询

    第k值,假定知道每个数的权值,对值域分块。

    对于整块,维护前(i)个块当中,值域在(j)块里以及值为(j)的数的个数,可以方便的询问。

    对于边角,直接记值域在(j)块里以及值为(j)的数的个数,显然(o(sqrt n))

    那么接下来只要先按值域块扫,确定第k值在哪个值域块内,然后块内扫一遍,复杂度(o(sqrt n))

    修改

    对于边角,大力重构,暴力修改 前(i)个块当中,值域在(j)块里以及值为(j)的数的个数。

    对于整块,可以维护一个并查集,每个点指向相同权值的位置,用top数组记录每种权值的并查集顶端位置。然后x->y就很轻松了对吧...从左到右逐块累加,修改 前(i)块 值域在(j)块里以及值为(j)的数的个数。

    总体复杂度(o((n+m) sqrt n))

    #include<bits/stdc++.h>
    #define rep(q,a,b) for(int q=a,q##_end_=b;q<=q##_end_;++q)
    #define dep(q,a,b) for(int q=a,q##_end_=b;q>=q##_end_;--q)
    #define mem(a,b) memset(a,b,sizeof a )
    #define debug(a) cerr<<#a<<' '<<a<<"___"<<endl
    using namespace std;
    bool cur1;
    char buf[10000000],*p1=buf,*p2=buf;
    #define Getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,10000000,stdin),p1==p2)?EOF:*p1++
    void in(int &r) {
        static char c;
        r=0;
        while(c=Getchar(),c<48);
        do r=(r<<1)+(r<<3)+(c^48);
        while(c=Getchar(),c>47);
    }
    const int mn=100005;
    const int BLK1=290;
    const int BLK2=320;
    int n,K,K1,val[mn],F[BLK2][BLK1],T[mn][BLK1];
    //F[i][j] 值域i块,在前j块里的数个数
    //T[i][j] 值i,在前j块里的数个数 
    int fa[mn];
    int find(int x){
        return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    int last[mn],top[BLK1][mn];
    #define get_val(x) val[find(x)]
    int rebuild(int id,int l1,int r1,int x,int y){
        int l=K*id,r=min(K*id+K-1,n),ct=0;
        int *tp=top[id];
        rep(q,l,r)val[q]=get_val(q),tp[val[q]]=0;
        rep(q,l,r){
            if(q>=l1&&q<=r1&&val[q]==x)val[q]=y,++ct;
            fa[q]=(!last[val[q]]?(tp[val[q]]=q+1,last[val[q]]=q+1):last[val[q]])-1;
        }
        rep(q,l,r)last[val[q]]=0;
        return ct;
    }
    void cg(int id,int v,int v1,int num){
        int *F1=F[v/K1],*F2=F[v1/K1],*T1=T[v],*T2=T[v1];
        rep(q,id,n/K){
            F1[q]-=num,F2[q]+=num,T1[q]-=num,T2[q]+=num;
        }
    }
    void change(int l,int r,int fr,int to){
        if(fr==to)return;
        int l_id=l/K,r_id=r/K;
        if(l_id==r_id){
            int ct=rebuild(l_id,l,r,fr,to);
            cg(l_id,fr,to,ct);
        }else{
            int *td,*F1=F[fr/K1],*F2=F[to/K1],*T1=T[fr],*T2=T[to],num=0;
            int ct=rebuild(l_id,l,l_id*K+K-1,fr,to);
    
            rep(q,l_id,r_id-1){
                F1[q]-=ct,F2[q]+=ct,T1[q]-=ct,T2[q]+=ct;
            }
            
            ct+=rebuild(r_id,r_id*K,r,fr,to);
            
            int ld=T1[l_id+1]-T1[l_id];
            rep(q,l_id+1,r_id-1){
                num+=ld;
                ld=T1[q+1]-T1[q];
                F1[q]-=num,F2[q]+=num,T1[q]-=num,T2[q]+=num;
                
                td=top[q];
                if(td[fr]){
                    if(td[to])fa[td[fr]-1]=td[to]-1;
                    else val[td[fr]-1]=to,td[to]=td[fr];
                    td[fr]=0;
                }
            }
            num+=ct;
            rep(q,r_id,n/K){
                F1[q]-=num,F2[q]+=num,T1[q]-=num,T2[q]+=num;
            }
        }
    }
    int X[BLK2],Y[mn];
    int ask(int l,int r,int k){
        int l_id=l/K,r_id=r/K;
        int ans=0;
        if(l_id==r_id){
            
            rep(q,l,r){
                int v=get_val(q);
                ++X[v/K1],++Y[v];
            }
            
            for(int q=0;;++q){
                if(X[q]>=k){
                    rep(w,q*K1,q*K1+K1-1){
                        if(Y[w]>=k){
                            ans=w;
                            break;
                        }
                        k-=Y[w];
                    }
                    break;
                }
                k-=X[q];
            }
            
            rep(q,l,r){
                int v=get_val(q);
                --X[v/K1],--Y[v];
            }
        }else{
            rep(q,l,l_id*K+K-1){
                int v=get_val(q);
                ++X[v/K1],++Y[v];
            }
            rep(q,r_id*K,r){
                int v=get_val(q);
                ++X[v/K1],++Y[v];
            }
            
            
            for(int q=0;;++q){
                int v=F[q][r_id-1]-F[q][l_id]+X[q];
                if(v>=k){
                    rep(w,q*K1,q*K1+K1-1){
                        if(T[w][r_id-1]-T[w][l_id]+Y[w]>=k){
                            ans=w;
                            break;
                        }
                        k-=T[w][r_id-1]-T[w][l_id]+Y[w];
                    }
                    break;
                }
                k-=v;
            }
            
            rep(q,l,l_id*K+K-1){
                int v=get_val(q);
                --X[v/K1],--Y[v];
            }
            rep(q,r_id*K,r){
                int v=get_val(q);
                --X[v/K1],--Y[v];
            }
        }
        return ans;
    }
    void init(){
        rep(q,0,n)fa[q]=q;
        rep(q,0,n/K){
            int *tp=top[q];
            rep(w,q*K,min(n,q*K+K-1)){
                fa[w]=(!last[val[w]]?(tp[val[w]]=w+1,last[val[w]]=w+1):last[val[w]])-1;
            }
            rep(w,q*K,min(n,q*K+K-1))last[val[w]]=0,++F[val[w]/K1][q],++T[val[w]][q];
            if(q){
                rep(w,0,100000/K1)F[w][q]+=F[w][q-1];
                rep(w,0,100000)T[w][q]+=T[w][q-1];
            }
        }
    }
    bool cur2;
    int main(){
    //	cerr<<(&cur2-&cur1)/1024.0/1024<<endl;
        in(n);
        K=sqrt(n)*1.1+1,K1=320;
        --n;
        int m,ty,a,b,x,y;
        in(m);
        rep(q,0,n)in(val[q]);
        init();
        while(m--){
            in(ty),in(a),in(b),in(x);
            if(ty==1)in(y),change(a-1,b-1,x,y);
            else printf("%d
    ",ask(a-1,b-1,x));
        }
        return 0;
    }
    
  • 相关阅读:
    常用命令之mongodb
    常用之juc
    常用命令
    WSL2错误Error 0x1bc解决
    sudo:Unable to stat '/etc/sudoers': Permission Denied 解决办法
    CPIO写入ROOTFS到磁盘分区
    getElementsByClassName
    PetaLinux通过fw_printenv访问u-boot中的环境变量
    1. 两数之和
    find xargs grep查找文件及文件内容
  • 原文地址:https://www.cnblogs.com/klauralee/p/10925775.html
Copyright © 2011-2022 走看看