zoukankan      html  css  js  c++  java
  • BZOJ 3065 带插入区间K小值(sag套线段树)

    3065: 带插入区间K小值

    Time Limit: 60 Sec  Memory Limit: 512 MB
    Submit: 4696  Solved: 1527
    [Submit][Status][Discuss]

    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组数据。

    Source

    作者 vfleaking

    转自大神:http://hzwer.com/4572.html

    替罪羊树是一种不用旋转的平衡树,若一棵子树的左或右子树大小超过其大小55%-80%则暴力重构这棵子树,以此来维护平衡性,每个结点的期望重构次数是logn,实现可以自己脑补一下

    在替罪羊树每个结点放一棵包含该子树所有结点的权值线段树,也就是平衡树套权值线段树

    1、由于外层是平衡树,那么就能实现插入一个结点:找到它的位置,在根到其路径上所有结点的线段树中插入这个值

    2、查询区间第K大:找到这个区间包含若干棵子树,拿出他们的根的权值线段树,一起做个二分

    3、修改与插入类似

    4、当外层平衡树失衡的时候重构之,将某个子树自下而上线段树合并

    然后就是考验数据结构的能力了QAQ

    由于内存不够,我们还需要回收垃圾,即对数组的重复使用

    写的时候遇到了点麻烦,重构的时候我所有结点暴力插入了,所以我的复杂度是qlog^3n,否则应是qlog^2n

    代码:

      1 #include<bits/stdc++.h>
      2 #define alpha 0.75
      3 #define N 10000005
      4 using namespace std;
      5 inline int read()
      6 {
      7     int x=0,f=1;;char ch=getchar();
      8     while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
      9     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     10     return x*f;
     11 }
     12 int tmp;
     13 int n,m,sz,lastans,root;
     14 int v[70005],dfn[70005],rt[70005],ls[70005],rs[70005];
     15 struct seg{
     16     int l,r,sum;
     17 } a[N];
     18 vector<int> rec,t,p;
     19 inline int newnode()
     20 {
     21     if(!rec.size()) return ++sz;
     22     else 
     23     {
     24         int k=rec.back();rec.pop_back();
     25         return k;
     26     }
     27 }
     28 inline void reclaim(int &x)
     29 {
     30     if(!x) return;
     31     rec.push_back(x);
     32     reclaim(a[x].l);reclaim(a[x].r);
     33     a[x].sum=0;x=0;
     34 }
     35 inline void insert(int &k,int l,int r,int val,int f)
     36 {
     37     if(!k) k=newnode();
     38     if(l==r){ a[k].sum+=f; return; }
     39     int mid=(l+r)>>1; 
     40     if(val<=mid) insert(a[k].l,l,mid,val,f);
     41     else insert(a[k].r,mid+1,r,val,f);
     42     a[k].sum=a[a[k].l].sum+a[a[k].r].sum;
     43     if(!a[k].sum)reclaim(k);
     44 }
     45 inline void build(int &k,int l,int r)
     46 {
     47     if(l>r) return;
     48     if(l==r)
     49     {
     50         k=dfn[l];
     51         insert(rt[k],0,70000,v[k],1);
     52         return;
     53     }
     54     int mid=(l+r)>>1; k=dfn[mid];
     55     build(ls[k],l,mid-1); build(rs[k],mid+1,r);
     56     for(int i=l;i<=r;i++) insert(rt[k],0,70000,v[dfn[i]],1);
     57 }
     58 inline void del(int &x)
     59 {
     60     if(!x) return;
     61     reclaim(rt[x]); del(ls[x]);
     62     p.push_back(x); del(rs[x]);
     63     x=0;
     64 }
     65 inline void rebuild(int &x)
     66 {
     67     del(x); int s1=p.size();
     68     for(int i=1;i<=s1;i++) dfn[i]=p[i-1];
     69     build(x,1,s1);
     70     p.clear();
     71 }
     72 inline int modify(int k,int x,int val)
     73 {
     74     insert(rt[k],0,70000,val,1);
     75     int t,L=a[rt[ls[k]]].sum;
     76     if(L+1==x){ t=v[k];v[k]=val; }    
     77     else if(L>=x) t=modify(ls[k],x,val);
     78     else t=modify(rs[k],x-L-1,val);
     79     insert(rt[k],0,70000,t,-1);
     80     return t;
     81 }
     82 inline void query(int k,int l,int r)
     83 {
     84     int L=a[rt[ls[k]]].sum,R=a[rt[k]].sum;
     85     if(l==1&&r==R){ t.push_back(rt[k]);return; }
     86     if(l<=L+1&&r>=L+1) p.push_back(v[k]);
     87     if(r<=L) query(ls[k],l,r);
     88     else if(l>L+1) query(rs[k],l-L-1,r-L-1);
     89     else 
     90     {
     91         if(l<=L)query(ls[k],l,L);
     92         if(R>L+1)query(rs[k],1,r-L-1);
     93     }
     94 }
     95 inline int solve_query(int L,int R,int K)
     96 {
     97     query(root,L,R); K--;
     98     int l=0,r=70000,s1=t.size(),s2=p.size();
     99     while(l<r)
    100     {
    101         int mid=(l+r)>>1,sum=0;
    102         for(int i=0;i<s1;i++) sum+=a[a[t[i]].l].sum;
    103         for(int i=0;i<s2;i++)
    104             if(p[i]>=l&&p[i]<=mid) sum++;
    105         if(K<sum)
    106         {
    107             for(int i=0;i<s1;i++) t[i]=a[t[i]].l;
    108             r=mid;
    109         }
    110         else 
    111         {
    112             for(int i=0;i<s1;i++) t[i]=a[t[i]].r;
    113             l=mid+1; K-=sum;
    114         }
    115     }
    116     t.clear(); p.clear();
    117     return l;
    118 }
    119 inline void insert(int &k,int x,int val)
    120 {
    121     if(!k)
    122     {
    123         k=++n;
    124         insert(rt[k],0,70000,val,1);
    125         v[k]=val;
    126         return;
    127     }
    128     insert(rt[k],0,70000,val,1);
    129     int L=a[rt[ls[k]]].sum;
    130     if(L>=x) insert(ls[k],x,val);
    131     else insert(rs[k],x-L-1,val);
    132     if(a[rt[k]].sum*alpha>max(a[rt[ls[k]]].sum,a[rt[rs[k]]].sum))
    133     {
    134         if(tmp)
    135         {
    136             if(ls[k]==tmp) rebuild(ls[k]);
    137             else rebuild(rs[k]);
    138             tmp=0;
    139         }
    140     }
    141     else tmp=k;
    142 }
    143 int main()
    144 {
    145     n=read();
    146     for(int i=1;i<=n;i++) v[i]=read();
    147     for(int i=1;i<=n;i++) dfn[i]=i;
    148     build(root,1,n);
    149     m=read();
    150     char ch[2];int x,y,K;
    151     while(m--)
    152     {
    153         scanf("%s",ch);
    154         x=read();y=read();x^=lastans;y^=lastans;
    155         switch(ch[0])
    156         {
    157             case 'Q': K=read();K^=lastans;lastans=solve_query(x,y,K);printf("%d
    ",lastans); break;
    158             case 'M': modify(root,x,y); break;
    159             case 'I': tmp=0;insert(root,x-1,y);if(tmp){ tmp=0;rebuild(root); } break;
    160         }
    161     }
    162     return 0;
    163 }
    164   
    View Code
  • 相关阅读:
    Android&读取Sdcard中的歌曲,ListView操作
    委托从数据库出来的类型分类处理
    分类信息网站
    Managed DirectX +C# 开发(入门篇)(二)
    ZedGraph控件的使用属性和例子代码
    【转】 c#ZedGraph 控件属性
    ZedGraph
    基于Visual C#的DirectX开发实例教程
    C#常用开源类库收集
    狄更斯《双城记》开场白
  • 原文地址:https://www.cnblogs.com/csushl/p/9865900.html
Copyright © 2011-2022 走看看