zoukankan      html  css  js  c++  java
  • ZOJ2112 Dynamic Rankings (线段树套平衡树)(主席树)

    The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.

    Your task is to write a program for this computer, which

    - Reads N numbers from the input (1 <= N <= 50,000)

    - Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.

    Input

    The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.

    The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format

    Q i j k or
    C i t

    It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.

    There're NO breakline between two continuous test cases.


    <b< dd="">

    Output

    For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])

    There're NO breakline between two continuous test cases.

    Sample Input

    2
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3

    Sample Output

    3
    6
    3
    6

    第一次写树套树,而且应该是最基础的树套树,手抄大佬函数,自己整理成结构体。

    没看别人题解的时候再高数课上YY,以为是对于线段树的每个节点套一个平衡树,这样的话想了一下,开的空间大概是n*lgn*n,基本上是炸了的。

     但是好像没有必要每个节点建立一个Treap,每个Treap给n个节点。因为过于浪费。

    大佬们好像是只建立一个大Treap,但是有n个root,然后把空间分配到小Treap里面。

    但是这样空间开n*lgn*lgn,好像1000000的空间还是不够处理极限情况啊。。。不知道这么回事。

     copy from qscqesze 顾学姐?结合前两天写的线段树和Treap,我们两个的风格还是比较像的,所以我理解代码起来也比较快。ORZ。。。对于空间的问题,多做几个题再回头分析。

    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<cstring>
    #include<ctime>
    using namespace std;
    #define maxn 1000001
    int tmp=0;
    struct Treap
    {
        int root[maxn],sz,s[maxn],ch[maxn][2],v[maxn],w[maxn],rnd[maxn];//s是size,w是cnt 
        //rnd小根堆 
        void init()
        {
            memset(root,0,sizeof(root));
            sz=0;
        }
        void Update(int now)
        {
            s[now]=s[ch[now][0]]+s[ch[now][1]]+w[now];
        }
        void rotate(int &now,int p)
        {
            int t=ch[now][p];
            ch[now][p]=ch[t][1-p],ch[t][1-p]=now,s[t]=s[now];
            Update(now);now=t;//好像明白了为什么要替代:k得到儿子信息 
        }
        void Insert(int &now,int num)
        {
            if(!now){
                now=++sz;s[now]=w[now]=1;ch[now][0]=ch[now][1]=0;rnd[now]=rand();
                v[now]=num;return;
            }
            s[now]++;
            if(v[now]==num)w[now]++;
            else{
                int t=num>v[now];
                Insert(ch[now][t],num);
                if(rnd[ch[now][t]]<rnd[now])
                    rotate(now,t);
            }
        }
        void Del(int &now,int num)//code better than mine before
        {
            if(v[now]==num){
                if(w[now]>1){
                    w[now]--;
                    s[now]--;
                    return;
                }
                if(ch[now][0]*ch[now][1]==0)
                    now=ch[now][0]+ch[now][1];
                else  rotate(now,rnd[ch[now][0]]>rnd[ch[now][1]]),Del(now,num);
            }
            else {
                Del(ch[now][num>v[now]],num);
                s[now]--;
            }
        }
        void Find(int now,int num)
        {
            if(!now) return;
            if(v[now]<=num){
                tmp+=s[ch[now][0]]+w[now];
                Find(ch[now][1],num);
            }
            else Find(ch[now][0],num);
        }
    }Tr;
    /////////////////////线段树
    void Seg_insert(int now,int l,int r,int x,int num)
    {
        Tr.Insert(Tr.root[now],num);
        if(l==r)return;
        int mid=(l+r)>>1;
        if(x<=mid)Seg_insert(now<<1,l,mid,x,num);
        else Seg_insert(now<<1|1,mid+1,r,x,num);
    }
    
    void Seg_change(int now,int l,int r,int x,int Now,int Pre)
    {
        Tr.Del(Tr.root[now],Pre);
        Tr.Insert(Tr.root[now],Now);
        if(l==r)return;
        int mid=(l+r)>>1;
        if(x<=mid)Seg_change(now<<1,l,mid,x,Now,Pre);
        else Seg_change(now<<1|1,mid+1,r,x,Now,Pre);
    }
    void Seg_query(int now,int l,int r,int L,int R,int num)
    {
        if(l==L&&r==R)
        {
            Tr.Find(Tr.root[now],num);
            return;
        }
        int mid = (l+r)>>1;
        if(mid>=R)
            Seg_query(now<<1,l,mid,L,R,num);
        else if(mid<L)
            Seg_query(now<<1|1,mid+1,r,L,R,num);
        else{
            Seg_query(now<<1,l,mid,L,mid,num);
            Seg_query(now<<1|1,mid+1,r,mid+1,R,num);
        }
    }
    ///////////////////////////
    int a[maxn];
    int main()
    {
        int T;scanf("%d",&T);
        while(T--)
        {
            Tr.init();
            int n,m;scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
                Seg_insert(1,1,n,i,a[i]);
            }
            char op[3];
            for(int i=1;i<=m;i++){
                scanf("%s",op);
                if(op[0]=='C'){
                    int x,y;scanf("%d%d",&x,&y);
                    Seg_change(1,1,n,x,y,a[x]);
                    a[x]=y;
                }
                else{
                    int x,y,z;scanf("%d%d%d",&x,&y,&z);
                    int l = 0,r = 1e9;
                    while(l<=r){
                        int mid = (l+r)>>1;
                        tmp=0; Seg_query(1,1,n,x,y,mid);
                        if(tmp>=z)r=mid-1;
                        else l=mid+1;
                    }
                    printf("%d
    ",l);
                }
            }
        }
        return 0; 
    }

    (2700ms左右);

     这题还有主席树(200ms左右)

    代码见:http://www.cnblogs.com/hua-dong/p/7931778.html

  • 相关阅读:
    linux文件上传
    ios base64图片上传失败问题
    ERROR 1267 (HY000): Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation '='
    配置SQL Server 2012 AlwaysOn ——step3 配置数据库
    配置SQL Server 2012 AlwaysOn ——step2 建立群集
    配置SQL Server 2012 AlwaysOn ——step1 建立AD域及DNS配置
    适应多场景应用的web系统架构探讨
    住院病案首页数据填写质量规范
    病案首页规范
    vs2015离线使用nuget
  • 原文地址:https://www.cnblogs.com/hua-dong/p/7920779.html
Copyright © 2011-2022 走看看