zoukankan      html  css  js  c++  java
  • BZOJ_1901_&_ZJU_2112_Dynamic_Rankings_(主席树+树状数组/线段树+(Treap/Splay))

    描述


    http://www.lydsy.com/JudgeOnline/problem.php?id=1901

    给出一个长度为n的数列A,有m次询问,询问分两种:1.修改某一位置的值;2.求区间[l,r]内的第k小的值.

    1901: Zju2112 Dynamic Rankings

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 6716  Solved: 2793
    [Submit][Status][Discuss]

    Description

    给 定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在 a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对 改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令, 你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示 a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

    Input

    对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

    Output

    Sample Input

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

    Sample Output

    3
    6

    HINT

    20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。

    Source

    分析


    对于只有第一种询问的问题: POJ_2104_Kth(主席树)

    现在要求动态.我们思考这样一个问题:把求区间第k小的问题变成求区间和值的问题,这个好解决吧?对于静态的问题,我们使用前缀和即可解决,那么对于动态的呢?使用树状数组维护前缀和.那么现在把问题变回求区间第k小值的问题.对于静态的问题,我们还是使用前缀和的思想,不过这一次每个前缀和不再是代表[1,i]的和值,而是[1,i]的一棵线段树,然后找到区间左右断点,相减即可得到答案.者可以理解为"前缀和套线段树",并且我们使用可持久化的思想大大减小空间开销.那么对于动态的问题,我们还是使用树状数组的思想,不过这一次每个点不再代表[i-lowbit(i)+1,i]的和值,而是代表[i-lowbit[i]+1,i]的一棵线段树.问题就迎刃而解了.

    注意:

    1.这里的每一个点代表的主席树刚开始都是由root[i](=0)建立的,之后修改的时候已有的就不需要再建立了.由于主席树的空间需求不好估计(对于这样的问题,空间的上界是(n+m)(logn*logn),但实际上远远用不到),虽然也可以写成每次修改无论之前有没有都直接复制一份,但是在空间不确定的情况下,写成前一种不容易爆炸.

    前一种:

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 
     5 const int maxn=10000+5;
     6 struct node{ int l,r,s; }t[maxn*400];
     7 struct qry{ int a,b,c; }q[maxn];
     8 int n,m,cnt,tot,num;
     9 int a[maxn],b[maxn<<1],root[maxn],L[maxn],R[maxn];
    10 
    11 inline int lowbit(int x){ return x&(-x); }
    12 void update(int l,int r,int &pos,int d,int s){
    13     if(!pos)t[++cnt]=t[pos], pos=cnt;
    14     t[pos].s+=s;
    15     if(l==r) return;
    16     int mid=(l+r)/2;
    17     if(d<=mid) update(l,mid,t[pos].l,d,s);
    18     else update(mid+1,r,t[pos].r,d,s);
    19 }
    20 void change(int x,int d,int s){ for(;x<=n;x+=lowbit(x)) update(1,num,root[x],d,s); }
    21 int query(int l,int r,int k,int cl,int cr){
    22     if(l==r) return l;
    23     int suml=0,sumr=0;
    24     for(int i=1;i<=cl;i++) suml+=t[t[L[i]].l].s;
    25     for(int i=1;i<=cr;i++) sumr+=t[t[R[i]].l].s;
    26     int s=sumr-suml,mid=(l+r)/2;
    27     if(k<=s){
    28         for(int i=1;i<=cl;i++) L[i]=t[L[i]].l;
    29         for(int i=1;i<=cr;i++) R[i]=t[R[i]].l;
    30         return query(l,mid,k,cl,cr);
    31     }
    32     else{
    33         for(int i=1;i<=cl;i++) L[i]=t[L[i]].r;
    34         for(int i=1;i<=cr;i++) R[i]=t[R[i]].r;
    35         return query(mid+1,r,k-s,cl,cr);
    36     }
    37 }
    38 int get_ans(int l,int r,int k){
    39     int cl,cr;
    40     for(cl=0;l>0;l-=lowbit(l)) L[++cl]=root[l];
    41     for(cr=0;r>0;r-=lowbit(r)) R[++cr]=root[r];
    42     return query(1,num,k,cl,cr);
    43 }
    44 int main(){
    45     scanf("%d%d",&n,&m);
    46     char c;
    47     for(int i=1;i<=n;i++) scanf("%d",&a[i]), b[++tot]=a[i];
    48     for(int i=1;i<=m;i++){
    49         for(c=getchar();c<'A'||c>'Z';c=getchar());
    50         scanf("%d%d",&q[i].a,&q[i].b);
    51         if(c=='Q') scanf("%d",&q[i].c);
    52         else b[++tot]=q[i].b;
    53     }
    54     sort(b+1,b+1+tot);
    55     b[tot+1]=0x7fffffff;
    56     for(int i=1;i<=tot;i++) if(b[i]!=b[i+1]) b[++num]=b[i];
    57     for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+num,a[i])-b;
    58     for(int i=1;i<=n;i++) change(i,a[i],1);
    59     for(int i=1;i<=m;i++){
    60         if(q[i].c) printf("%d
    ",b[get_ans(q[i].a-1,q[i].b,q[i].c)]);
    61         else{
    62             change(q[i].a,a[q[i].a],-1);
    63             a[q[i].a]=lower_bound(b+1,b+1+num,q[i].b)-b;
    64             change(q[i].a,a[q[i].a],1);
    65         }
    66     }
    67     return 0;
    68 }
    69 
    70 前一种
    View Code

    后一种:

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 
     5 const int maxn=10000+5;
     6 struct node{ int l,r,s; }t[maxn*400];
     7 struct qry{ int a,b,c; }q[maxn];
     8 int n,m,cnt,tot,num;
     9 int a[maxn],b[maxn<<1],root[maxn],L[maxn],R[maxn];
    10 
    11 inline int lowbit(int x){ return x&(-x); }
    12 void update(int l,int r,int &pos,int d,int s){
    13     t[++cnt]=t[pos]; t[cnt].s+=s; pos=cnt;
    14     if(l==r) return;
    15     int mid=(l+r)/2;
    16     if(d<=mid) update(l,mid,t[pos].l,d,s);
    17     else update(mid+1,r,t[pos].r,d,s);
    18 }
    19 void change(int x,int d,int s){ for(;x<=n;x+=lowbit(x)) update(1,num,root[x],d,s); }
    20 int query(int l,int r,int k,int cl,int cr){
    21     if(l==r) return l;
    22     int suml=0,sumr=0;
    23     for(int i=1;i<=cl;i++) suml+=t[t[L[i]].l].s;
    24     for(int i=1;i<=cr;i++) sumr+=t[t[R[i]].l].s;
    25     int s=sumr-suml,mid=(l+r)/2;
    26     if(k<=s){
    27         for(int i=1;i<=cl;i++) L[i]=t[L[i]].l;
    28         for(int i=1;i<=cr;i++) R[i]=t[R[i]].l;
    29         return query(l,mid,k,cl,cr);
    30     }
    31     else{
    32         for(int i=1;i<=cl;i++) L[i]=t[L[i]].r;
    33         for(int i=1;i<=cr;i++) R[i]=t[R[i]].r;
    34         return query(mid+1,r,k-s,cl,cr);
    35     }
    36 }
    37 int get_ans(int l,int r,int k){
    38     int cl,cr;
    39     for(cl=0;l>0;l-=lowbit(l)) L[++cl]=root[l];
    40     for(cr=0;r>0;r-=lowbit(r)) R[++cr]=root[r];
    41     return query(1,num,k,cl,cr);
    42 }
    43 int main(){
    44     scanf("%d%d",&n,&m);
    45     char c;
    46     for(int i=1;i<=n;i++) scanf("%d",&a[i]), b[++tot]=a[i];
    47     for(int i=1;i<=m;i++){
    48         for(c=getchar();c<'A'||c>'Z';c=getchar());
    49         scanf("%d%d",&q[i].a,&q[i].b);
    50         if(c=='Q') scanf("%d",&q[i].c);
    51         else b[++tot]=q[i].b;
    52     }
    53     sort(b+1,b+1+tot);
    54     b[tot+1]=0x7fffffff;
    55     for(int i=1;i<=tot;i++) if(b[i]!=b[i+1]) b[++num]=b[i];
    56     for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+num,a[i])-b;
    57     for(int i=1;i<=n;i++) change(i,a[i],1);
    58     for(int i=1;i<=m;i++){
    59         if(q[i].c) printf("%d
    ",b[get_ans(q[i].a-1,q[i].b,q[i].c)]);
    60         else{
    61             change(q[i].a,a[q[i].a],-1);
    62             a[q[i].a]=lower_bound(b+1,b+1+num,q[i].b)-b;
    63             change(q[i].a,a[q[i].a],1);
    64         }
    65     }
    66     return 0;
    67 }
    View Code


    p.s.这题可以用线段树套平衡树做(貌似树状数组套平衡树也是可以的?树状数组不太熟啊...)

    线段树+Treap:

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <algorithm>
      4 using namespace std;
      5 
      6 const int maxn=10000+5,oo=~0u>>1;
      7 int n,q;
      8 int a[maxn];
      9 char str[3];
     10 struct Treap{
     11     struct node{
     12         node* ch[2];
     13         int v,r,s,c;
     14         node(int v,node* t):v(v){ ch[0]=ch[1]=t; r=rand(); s=c=1; }
     15         void push_up(){ s=ch[0]->s+ch[1]->s+c; }
     16     }*root,*null;
     17     Treap(){
     18         null=new node(0,NULL);
     19         null->c=null->s=0; null->r=oo;
     20         root=null;
     21     }
     22     void rotate(node* &o,bool d){
     23         node* k=o->ch[!d]; o->ch[!d]=k->ch[d]; k->ch[d]=o;
     24         o->push_up(); k->push_up(); o=k;
     25     }
     26     void insert(node* &o,int x){
     27         if(o==null) o=new node(x,null);
     28         else{
     29             if(x==o->v) o->s++, o->c++;
     30             else{
     31                 bool d=x>o->v;
     32                 insert(o->ch[d],x);
     33                 if(o->ch[d]->r<o->r) rotate(o,!d);
     34                 o->push_up();
     35             }
     36         }
     37     }
     38     void remove(node* &o,int x){
     39         if(o->v==x){
     40             if(o->c>1) o->c--, o->s--;
     41             else{
     42                 if(o->ch[0]!=null&&o->ch[1]!=null){
     43                     bool d=o->ch[0]->r<o->ch[1]->r;
     44                     rotate(o,d); remove(o->ch[d],x); o->push_up();
     45                 }
     46                 else{
     47                     node* u=o;
     48                     o=o->ch[0]==null?o->ch[1]:o->ch[0];
     49                     delete u;
     50                 }
     51             }
     52         }
     53         else{
     54             bool d=x>o->v;
     55             remove(o->ch[d],x);
     56             o->push_up();
     57         }
     58     }
     59     int rank(int x){
     60         int ret=0;
     61         for(node* t=root;t!=null;){
     62             int s=t->ch[0]->s+t->c;
     63             if(x>t->v) ret+=s, t=t->ch[1];
     64             else t=t->ch[0];
     65         }
     66         return ret;
     67     }
     68     int pre(int x){
     69         int ret=-oo;
     70         for(node* t=root;t!=null;){
     71             if(t->v<x) ret=t->v, t=t->ch[1];
     72             else t=t->ch[0];
     73         }
     74         return ret;
     75     }
     76 };
     77 struct Segment_Tree{
     78     Treap tree[maxn*4];
     79     void build_tree(int l,int r,int k){
     80         for(int i=l;i<=r;i++) tree[k].insert(tree[k].root,a[i]);
     81         if(l==r) return;
     82         int mid=l+(r-l)/2;
     83         build_tree(l,mid,k<<1); build_tree(mid+1,r,k<<1|1);
     84     }
     85     int get_rank(int l,int r,int k,int x,int y,int X){
     86         if(l==x&&r==y) return tree[k].rank(X);
     87         int mid=l+(r-l)/2;
     88         if(y<=mid) return get_rank(l,mid,k<<1,x,y,X);
     89         else if(x>mid) return get_rank(mid+1,r,k<<1|1,x,y,X);
     90         else return get_rank(l,mid,k<<1,x,mid,X)+get_rank(mid+1,r,k<<1|1,mid+1,y,X);
     91     }
     92     void change(int l,int r,int k,int id,int x){
     93         tree[k].remove(tree[k].root,a[id]);
     94         tree[k].insert(tree[k].root,x);
     95         if(l==r) return;
     96         int mid=l+(r-l)/2;
     97         if(id<=mid) change(l,mid,k<<1,id,x);
     98         else change(mid+1,r,k<<1|1,id,x);
     99     }
    100     int get_pre(int l,int r,int k,int x,int y,int X){
    101         if(l==x&&r==y) return tree[k].pre(X);
    102         int mid=l+(r-l)/2;
    103         if(y<=mid) return get_pre(l,mid,k<<1,x,y,X);
    104         else if(x>mid) return get_pre(mid+1,r,k<<1|1,x,y,X);
    105         else return max(get_pre(l,mid,k<<1,x,mid,X),get_pre(mid+1,r,k<<1|1,mid+1,y,X));
    106     }
    107     int get_kth(int x,int y,int k){
    108         long long l=-oo,r=oo;
    109         while(l<r){
    110             int mid=(int)(l+(r-l)/2);
    111             int tmp=get_rank(1,n,1,x,y,mid)+1;
    112             if(tmp<=k) l=mid+1;
    113             else r=mid;
    114         }
    115         return get_pre(1,n,1,x,y,l);
    116     }
    117 }T;
    118 
    119 int main(){
    120     scanf("%d%d",&n,&q);
    121     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    122     T.build_tree(1,n,1);
    123     for(int i=1;i<=q;i++){
    124         scanf("%s",str);
    125         int l,r,k,id,x;
    126         if(str[0]=='Q'){
    127             scanf("%d%d%d",&l,&r,&k);
    128             printf("%d
    ",T.get_kth(l,r,k));
    129         }
    130         else{
    131             scanf("%d%d",&id,&x);
    132             T.change(1,n,1,id,x);
    133             a[id]=x;
    134         }
    135     }
    136     return 0;
    137 }
    View Code
  • 相关阅读:
    决战72hours
    学习中的十七条建议
    数学建模终结篇
    数学建模(7)建模开始
    ASP升级程序
    为blog挑选logo
    Mysql源代码分析系列(4): 主要调用流程(续)转载
    AS学习步骤
    什么是敏捷软件测试[转]
    Mysql源代码分析(6): Plugin架构介绍(续)转载
  • 原文地址:https://www.cnblogs.com/Sunnie69/p/5511626.html
Copyright © 2011-2022 走看看