• BZOJ 4923: [Lydsy1706月赛]K小值查询 Splay + 思维


    Description

    维护一个长度为n的正整数序列a_1,a_2,...,a_n,支持以下两种操作:
    1 k,将序列a从小到大排序,输出a_k的值。
    2 k,将所有严格大于k的数a_i减去k。

    Input

    第一行包含两个正整数n,m(1<=n,m<=100000),分别表示序列的长度和操作的个数。
    第二行包含n个正整数a_1,a_2,...,a_n(1<=a_i<=10^9),分别表示序列中的每个元素。
    接下来m行,每行两个正整数op(1<=op<=2),k,若op=1,则1<=k<=n;若op=2,则1<=k<=10^9;依次描述每个操作。

    Output

    输出若干行,对于每个询问输出一行一个整数,即第k小的值。
     

    感觉怎么做都没什么思路.
    学长说正解是分类讨论.
    还真是分类讨论...
    可以将所有数分为两种:小于等于 $k$ 的,大于 $k$ 的.
    前一部分的数值是不变的,大于 $k$ 的数值都要变.
    而我们还可以把大于 $k$ 的再分成大于 $2k$ 的和 $k<=a_{i}<=2k.$
    而将 $a_{i}in[k,2k]$ 的数减掉 $k$ 就相当于至少 / 2.
    因为没有加法操作,所以每一个数至多会减少 $log(10^9)$ 次.
    所以可以每一次用 $splay$ 将 $a_{i}in[k,2k]$ 之间的数字提取出来,直接暴力减掉 $k$ 并重新插进平衡树.

    #include <bits/stdc++.h>
    using namespace std; 
    typedef long long ll; 
    const int maxn=100003; 
    namespace IO {  
        void setIO(string s) {
            string in=s+".in"; 
            string out=s+".out"; 
            freopen(in.c_str(),"r",stdin);
            freopen(out.c_str(),"w",stdout); 
        } 
        char *p1,*p2,buf[100000];
        #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
        int rd() {
            int x=0; 
            char c=nc(); 
            while(c<48) c=nc(); 
            while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); 
            return x;
        }
    };   
    int root; 
    int arr[maxn];   
    struct Splay { 
        #define lson ch[x][0] 
        #define rson ch[x][1] 
        stack<int>S; 
        int cnt,tp; 
        int ch[maxn][2],f[maxn],val[maxn],siz[maxn],tag[maxn],key[maxn];      
        void init() {
            for(int i=1;i<maxn;++i) S.push(i);    
        }      
        int newnode() {
            int x=S.top();S.pop(); 
            return x;    
        }
        void mark(int x,int d) { 
            val[x]-=d, tag[x]+=d;   
        }
        int get(int x) {
            return ch[f[x]][1]==x; 
        }
        void pushup(int x) {
            siz[x]=siz[lson]+siz[rson]+1;    
        }   
        void pushdown(int x) {
            if(tag[x]) mark(lson,tag[x]),mark(rson,tag[x]),tag[x]=0;  
        }
        void rotate(int x) {
            int old=f[x],fold=f[old],which=get(x); 
            ch[old][which]=ch[x][which^1],f[ch[old][which]]=old; 
            ch[x][which^1]=old,f[old]=x,f[x]=fold; 
            if(fold) ch[fold][ch[fold][1]==old]=x; 
            pushup(old),pushup(x); 
        }
        void splay(int x,int &tar) {
            int u=f[tar],fa; 
            for(;(fa=f[x])^u;rotate(x)) 
                if(f[fa]^u) 
                    rotate(get(fa)==get(x)?fa:x); 
            tar=x; 
        }
        int pre(int v) {
            int x=root,re=0; 
            while(x) { 
                pushdown(x);   
                if(val[x]<=v) re=x,x=rson;  
                else x=lson;    
            }    
            return re;   
        }         
        int nxt(int v) {
            int x=root,re=0; 
            while(x) {
                pushdown(x); 
                if(val[x]>=v) re=x,x=lson;   
                else x=rson; 
            } 
            return re;   
        } 
        void build(int &x,int ff,int l,int r) {
            x=newnode();  
            int mid=(l+r)>>1;  
            f[x]=ff,val[x]=arr[mid],siz[x]=1;   
            if(l<mid) build(lson,x,l,mid-1);  
            if(r>mid) build(rson,x,mid+1,r);     
            pushup(x);     
        }
        int insert(int &x,int ff,int k) {
            if(!x) {
                x=newnode();   
                f[x]=ff,val[x]=k,siz[x]=1; 
                pushup(x);    
                return x;     
            } 
            pushdown(x); 
            int a=insert(ch[x][k>val[x]],x,k);   
            pushup(x);  
            return a;     
        }
        void dfs(int x) {
            if(!x) return;  
            pushdown(x); 
            key[++tp]=val[x];       
            if(lson) dfs(lson); 
            if(rson) dfs(rson);  
            S.push(x);   
            ch[x][0]=ch[x][1]=f[x]=val[x]=siz[x]=tag[x]=0;                    
        }
        int kth(int k) {
            int x=root;  
            while(1) {
                pushdown(x);  
                if(k>siz[lson]) { 
                    k-=(siz[lson]+1); 
                    if(k==0) return val[x];   
                    else x=rson;   
                }
                else x=lson;   
            }
        }
        void solve(int k) { 
            int pr=pre(k),nx=nxt(k<<1);  
            if(!pr) mark(root,k);   
            else if(!nx) {
                splay(pr,root);   
                int a=ch[root][1];  
                ch[root][1]=f[ch[root][1]]=0; 
                pushup(root);         
                tp=0; 
                dfs(a);   
                for(int i=1;i<=tp;++i) {
                    int cc=insert(root,0,key[i]-k); 
                    if(i%6==0) splay(cc,root);  
                }
            }
            else {    
                splay(pr,root),splay(nx,ch[root][1]);
                int a=ch[ch[root][1]][0];        
                ch[ch[root][1]][0]=0, pushup(ch[root][1]);        
                tp=0, dfs(a);    
                mark(ch[root][1], k);     
                for(int i=1;i<=tp;++i) {
                    int cc=insert(root,0,key[i]-k); 
                    if(i%6==0) splay(cc,root);  
                }
            }
        }
        #undef lson 
        #undef rson
    }tr; 
    int main() { 
        using namespace IO;  
        // setIO("input");   
        tr.init();    
        int n,m; 
        n=rd(),m=rd(); 
        for(int i=1;i<=n;++i) arr[i]=rd();  
        sort(arr+1,arr+1+n);
        tr.build(root,0,1,n);     
        for(int cas=1;cas<=m;++cas) {
            int op,k; 
            op=rd(),k=rd();  
            if(op==1) printf("%d
    ",tr.kth(k));  
            else tr.solve(k);  
        } 
        return 0; 
    }
    

      

  • 相关阅读:
    嵌入式 coredump
    CentOS7 systemctrl管理的服务,open files的神坑
    Linux 服务器网络流量查看工具
    shiro源码篇
    google guava
    Docker虚拟化管理:30分钟教你学会用Docker
    Shiro结合Redis实现分布式或集群环境下的Session共享
    Springboot整合redis
    Git分支操作方法
    Redis启动和在注册到windows服务
  • 原文地址:https://www.cnblogs.com/guangheli/p/11274047.html
Copyright © 2020-2023  润新知