zoukankan      html  css  js  c++  java
  • bzoj 3065: 带插入区间K小值 替罪羊树 && AC300

    3065: 带插入区间K小值

    Time Limit: 60 Sec  Memory Limit: 512 MB
    Submit: 1062  Solved: 253
    [Submit][Status]

    Description

    从 前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i]。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一 下,查询区间k小值。他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少。
    这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
    这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
    这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
    这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
    请你帮一帮伏特吧。
    快捷版题意:带插入、修改的区间k小值在线查询。

    Input

    第一行一个正整数n,表示原来有n只跳蚤排成一行做早操。
    第二行有n个用空格隔开的非负整数,从左至右代表每只跳蚤的弹跳力。
    第三行一个正整数q,表示下面有多少个操作。
    下面一共q行,一共三种操作对原序列的操作:(假设此时一共m只跳蚤)
    1. Q x y k: 询问从左至右第x只跳蚤到从左至右第y只跳蚤中,弹跳力第k小的跳蚤的弹跳力是多少。
        (1 <= x <= y <= m, 1 <= k <= y - x + 1)
    2. M x val: 将从左至右第x只跳蚤的弹跳力改为val。
        (1 <= x <= m)
    3. I x val: 在从左至右第x只跳蚤的前面插入一只弹跳力为val的跳蚤。即插入后从左至右第x只跳蚤是我刚插入的跳蚤。
        (1 <= x <= m + 1)

    为了体现在线操作,设lastAns为上一次查询的时候程序输出的结果,如果之前没有查询过,则lastAns = 0。
    则输入的时候实际是:
    Q _x _y _k ------> 表示 Q _x^lastAns _y^lastAns _k^lastAns
    M _x _val  ------> 表示 M _x^lastAns _val^lastAns
    I _x _val  ------> 表示 I _x^lastAns _val^lastAns
    简单来说就是操作中输入的整数都要异或上一次询问的结果进行解码。

    (祝Pascal的同学早日转C++,就不提供pascal版的描述了。)

    Output

    对于每个询问输出回答,每行一个回答。

    Sample Input

    10
    10 5 8 28 0 19 2 31 1 22
    30
    I 6 9
    M 1 11
    I 8 17
    M 1 31
    M 6 26
    Q 2 7 6
    I 23 30
    M 31 7
    I 22 27
    M 26 18
    Q 26 17 31
    I 5 2
    I 18 13
    Q 3 3 3
    I 27 19
    Q 23 23 30
    Q 5 13 5
    I 3 0
    M 15 27
    Q 0 28 13
    Q 3 29 11
    M 2 8
    Q 12 5 7
    I 30 19
    M 11 19
    Q 17 8 29
    M 29 4
    Q 3 0 12
    I 7 18
    M 29 27

    Sample Output

    28
    2
    31
    0
    14
    15
    14
    27
    15
    14

    HINT

    此题作为一个小小的研究来搞吧~做法有很多~不知道这题究竟有多少种做法。

    请自觉O(log^2n),我故意卡块状链表,块链A了的请受我深情一拜……

    A掉的同学请在Discuss里面简要说下自己的做法吧~

    原序列长度 <= 35000

    插入个数 <= 35000,修改个数 <= 70000,查询个数 <= 70000  ,0 <= 每时每刻的权值 <= 70000

    由于是OJ上的题,所以数据无梯度。为了防止卡OJ,本题只有4组数据。

      替罪羊树套线段树。

      AC300怎么能刷水题?然后就做了这样一道题。第一次编替罪羊树,觉得比较恶心。这道题由于内存使用量很吓人,所以必须用垃圾回收,这类内存越界的问题很难检查出来,但是也有一些窍门,比如说我们可以通过改变数组大小,观察RE的位置是否相同,每次处理输出当前使用量来查看使用趋势。

      这道题第一遍交RE,原因是有语句顺序问题导致一部分垃圾没有回收完全,内存超了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define MAXN 80000
    #define MAXV 70007
    #define MAXT 30000000
    #define alpha 0.7
    struct sgt_node
    {
            int lc,rc,tot;
    }sgt[MAXT];
    int topt=0;
    int stack2[MAXT];
    void Add_sgt(int &now,int l,int r,int pos,int delta)
    {
            if (!now)
            {
                    int old=now;
                    now=stack2[topt--];
                    if (topt<0)throw 3;
                    now=stack2[topt+1];
                    if (sgt[now].lc)stack2[++topt]=sgt[now].lc;
                    if (sgt[now].rc)stack2[++topt]=sgt[now].rc;
                    sgt[now]=sgt[old];
            }
            sgt[now].tot+=delta;
            if (l==r)return ;
            if (pos<=((l+r)>>1))
                    Add_sgt(sgt[now].lc,l,((l+r)>>1),pos,delta);
            else
                    Add_sgt(sgt[now].rc,((l+r)>>1)+1,r,pos,delta);
            if (sgt[now].tot==0)
            {
                    sgt[now].lc=sgt[now].rc=0;
                    stack2[++topt]=now;
                    now=0;
            }
    }
    int Qry_sgt(int &now,int l,int r,int x,int y)
    {
            if (!now)return 0;
            if (l==x && r==y)return sgt[now].tot;
            int mid=(l+r)>>1;
            if (y<=mid)
                    return Qry_sgt(sgt[now].lc,l,mid,x,y);
            else if (mid<x)
                    return Qry_sgt(sgt[now].rc,mid+1,r,x,y);
            else return Qry_sgt(sgt[now].lc,l,mid,x,mid)+Qry_sgt(sgt[now].rc,mid+1,r,mid+1,y);
    }
    struct Scap_tree
    {
            int lc,rc;
            int val,root;
            int siz;
    }scp[MAXN];
    int tops=-1,root=0;
    int stack[MAXN];
    int *Add_scp(int &now,int pos,int v)
    {
            if (!now)
            {
                    now=stack[tops--];
                    if (tops<0)throw 2;
                    scp[now].val=v;
                    Add_sgt(scp[now].root,0,MAXV,v,1);
                    scp[now].siz=1;
                    return NULL;
            }
            int* ret;
            if (pos==scp[scp[now].lc].siz+1)
                    ret=Add_scp(scp[now].lc,pos,v);
            else if (pos<=scp[scp[now].lc].siz)
                    ret=Add_scp(scp[now].lc,pos,v);
            else
                    ret=Add_scp(scp[now].rc,pos-scp[scp[now].lc].siz-1,v);
            Add_sgt(scp[now].root,0,MAXV,v,1);
            scp[now].siz++;
            if (max(scp[scp[now].lc].siz,scp[scp[now].rc].siz)>scp[now].siz*alpha)
                    return &now;
            return ret;
    }
    int Modify_scp(int now,int pos,int v)
    {
            Add_sgt(scp[now].root,0,MAXV,v,1);
            int t;
            if (scp[scp[now].lc].siz+1==pos)
            {
                    t=scp[now].val;
                    Add_sgt(scp[now].root,0,MAXV,t,-1);
                    scp[now].val=v;
                    return t;
            }
            if (scp[scp[now].lc].siz>=pos)
                    t=Modify_scp(scp[now].lc,pos,v);
            else
                    t=Modify_scp(scp[now].rc,pos-scp[scp[now].lc].siz-1,v);
            Add_sgt(scp[now].root,0,MAXV,t,-1);
            return t;
    }
    int vec[MAXN],topv=-1;
    void Scan(int now)
    {
            if (!now)return ;
            Scan(scp[now].lc);
            vec[++topv]=scp[now].val;
            Scan(scp[now].rc);
            stack[++tops]=now;
            stack2[++topt]=scp[now].root;
            scp[now].siz=scp[now].lc=scp[now].rc=scp[now].val=scp[now].root=0;
    }
    void Scan2(int now)
    {
            if (!now)return ;
            Scan2(scp[now].lc);
            printf("%d ",scp[now].val);
            Scan2(scp[now].rc);
    }
    void Build_scp(int &now,int l,int r)
    {
            if (l>r)return;
            now=stack[tops--];
            if (tops<0)throw 2;
            if (now>=MAXN)throw 1;
            scp[now].val=vec[(l+r)>>1];
            scp[now].root=0;
            scp[now].siz=r-l+1;
            for (int i=l;i<=r;i++)
                    Add_sgt(scp[now].root,0,MAXV,vec[i],1);
            Build_scp(scp[now].lc,l,((l+r)>>1)-1);
            Build_scp(scp[now].rc,((l+r)>>1)+1,r);
    }
    void Rebuild(int &now)
    {
            if (&now==NULL)return ;
            topv=-1;
            Scan(now);
            //for (int i=0;i<vec.size();i++)printf("%d ",vec[i]);printf("
    ");
            Build_scp(now,0,topv);
    }
    pair<int,int> lst[MAXN];
    int topl=-1;
    void Search_scp(int now,int l,int d,bool f)
    {
            if (!l)return ;
            if (l==scp[now].siz)
            {
                    lst[++topl]=make_pair(scp[now].root,d);
                    return ;
            }
            if (f==0)
            {
                    if (scp[scp[now].lc].siz>=l)
                    {
                            Search_scp(scp[now].lc,l,d,false);
                    }else 
                    {
                            lst[++topl]=make_pair(scp[now].root,d);
                            Search_scp(scp[now].rc,scp[now].siz-l,-d,true);
                    }
            }else
            {
                    if (scp[scp[now].rc].siz>=l)
                    {
                            Search_scp(scp[now].rc,l,d,true);
                    }else
                    {
                            lst[++topl]=make_pair(scp[now].root,d);
                            Search_scp(scp[now].lc,scp[now].siz-l,-d,false);
                    }
            }
    }
    int Query_kth(int ll,int rr,int rank)
    {
            topl=-1;
            Search_scp(root,ll-1,-1,false);
            Search_scp(root,rr,1,false);
            int l=0,r=MAXV;
            int mid;
            int sum;
            int i;
            while (l!=r)
            {
                    mid=(l+r)>>1;
                    sum=0;
                    for (i=0;i<=topl;i++)
                            sum+=sgt[sgt[lst[i].first].lc].tot*lst[i].second;
                    if (rank<=sum)
                    {
                            r=mid;
                            for (i=0;i<=topl;i++)
                                    lst[i].first=sgt[lst[i].first].lc;
                    }else
                    {
                            rank-=sum;
                            l=mid+1;
                            for (i=0;i<=topl;i++)
                                    lst[i].first=sgt[lst[i].first].rc;
                    }
            }
            return l;
    }
    int main()
    {
    //        freopen("input.txt","r",stdin);
    //        freopen("output.txt","w",stdout);
            int i,j,k,x,y,z,n,m;
            for (i=1;i<MAXN;i++)stack[++tops]=i;
            for (i=1;i<MAXT;i++)stack2[++topt]=i;
            scanf("%d",&n);
            for (i=0;i<n;i++)
            {
                    scanf("%d",&x);
                    vec[++topv]=x;
            }
            Build_scp(root,0,topv);
            scanf("%d
    ",&m);
            //Scan2(root);printf("
    ");
            char opt;
            int lastans=0;
            for (i=0;i<m;i++)
            {
                    scanf("%c",&opt);
                    if (i==38487)
                            --++i;
                    if (opt=='I')
                    {
                            scanf("%d %d
    ",&x,&y);
                            x^=lastans;y^=lastans;
                            Rebuild(*Add_scp(root,x,y));
                    }else if (opt=='M')
                    {
                            scanf("%d %d
    ",&x,&y);
                            x^=lastans;y^=lastans;
                            Modify_scp(root,x,y);
                    }else if (opt=='Q')
                    {
                            scanf("%d %d %d
    ",&x,&y,&z);
                            x^=lastans;y^=lastans;z^=lastans;
                            printf("%d
    ",lastans=Query_kth(x,y,z));
                    }
                    //printf("%d %d %d
    ",i,tops,topt);
            }
    }

    by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

    本博客已停用,新博客地址:http://mhy12345.xyz

  • 相关阅读:
    Linux CAT与ECHO命令详解
    查看linux版本信息
    kubernetes(一)
    Chrome不安装插件实现页面长截图
    centos 升级glibc-2.17
    redis修改大key报Argument list too long的解决办法
    mysql打印用户权限的小技巧
    Centos6.5 自带的Python2.6.6 如何安装setuptools和pip
    TCP三次握手过程中涉及的队列知识的学习
    Docker volume权限导致的几个问题
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4204834.html
Copyright © 2011-2022 走看看