bzoj 3065

3065: 带插入区间K小值

Time Limit: 60 Sec  Memory Limit: 512 MB
Submit: 5067  Solved: 1658
[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组数据。

本题常见的做法有两种: 一种是分块,另外一种是替罪羊树套权值线段树(需要进行线段树合并操作) 
 
 
方法1: 我写了一个分块,bzoj30s,主要是由于用到了vector,如果不用vector,肯定还可以更快。 
 
 
  1 #include<bits/stdc++.h>
  2 using namespace std; 
  3 int const N=70000+10;  
  4 int const B=500;  
  5 #define  st(x)  ((x-1)*B+1)  
  6 #define  ed(x)  min(n,x*B)   
  7 #define  id(x)  ((x-1)/B+1)   
  8 vector<int> a[500],b[500];  
  9 int n,t[N],q,sum;  
 10 int calc(int x,int y,int mid){
 11   int tx,ty,k1=0,k2=0;    
 12   for(tx=1;tx<=sum && k1<x;tx++) k1+=a[tx].size();  
 13   tx--; k1-=a[tx].size();  
 14   for(ty=1;ty<=sum && k2<y;ty++) k2+=a[ty].size();  
 15   ty--; k2-=a[ty].size();  
 16   int s=0;  
 17   int sx=x-k1-1;  
 18   int sy=y-k2-1;  
 19   if(tx==ty){
 20     for(int i=sx;i<=sy;i++)  
 21       if(a[tx][i]<=mid) s++;  
 22     return s;  
 23   }
 24   for(int i=sx;i<a[tx].size();i++)  
 25     if(a[tx][i]<=mid) s++;  
 26   for(int i=0;i<=sy;i++)
 27     if(a[ty][i]<=mid) s++;  
 28   for(int i=tx+1;i<=ty-1;i++){
 29     int k=upper_bound(b[i].begin(),b[i].end(),mid)-b[i].begin();   
 30     s+=k;  
 31   }
 32   return s;  
 33 }
 34 int main(){
 35     scanf("%d",&n);  
 36     for(int i=1;i<=n;i++) 
 37         scanf("%d",&t[i]);  
 38     sum=id(n);  
 39     for(int i=1;i<=sum;i++){
 40         for(int j=st(i);j<=ed(i);j++){
 41             a[i].push_back(t[j]);  
 42             b[i].push_back(t[j]); 
 43         }
 44         sort(b[i].begin(),b[i].end());  
 45     } 
 46   int last=0;  
 47   scanf("%d",&q);  
 48   while (q--){
 49     char s[2];  
 50     scanf("%s",s);  
 51     if(s[0]=='Q'){
 52       int l=0,r=N,x,y,k; 
 53       scanf("%d%d%d",&x,&y,&k);  
 54       x^=last;y^=last;k^=last;  
 55       while (l<r){
 56         int mid=(l+r)/2;  
 57         if(calc(x,y,mid)>=k)r=mid;  
 58         else l=mid+1; 
 59       } 
 60       printf("%d\n",last=l);  
 61     }
 62     if(s[0]=='M'){
 63       int x,y;  
 64       scanf("%d%d",&x,&y); 
 65       x^=last;y^=last;  
 66       int k=0,i;    
 67       for(i=1;i<=sum && k<x;i++) k+=a[i].size(); 
 68       i--;    
 69       k-=a[i].size();   
 70       int v=a[i][x-k-1];
 71       a[i][x-k-1]=y;  
 72       for(int j=0;j<b[i].size();j++)  
 73         if(b[i][j]==v){
 74           b[i][j]=y;  
 75           sort(b[i].begin(),b[i].end());   
 76           break;  
 77         }  
 78     }
 79     if(s[0]=='I'){
 80       int x,y;  
 81       scanf("%d%d",&x,&y) ; 
 82       x^=last;y^=last;  
 83       int k=0,i; n++;  
 84       for(i=1;i<=sum && k<x;i++) k+=a[i].size();  
 85       i--;  
 86       k-=a[i].size();  
 87       int t=x-k-1;  
 88       a[i].insert(a[i].begin()+t,y);  
 89       b[i].push_back(y); 
 90       sort(b[i].begin(),b[i].end());  
 91       if(a[i].size()>=2*B){
 92         for(int j=sum;j>i;j--)  
 93           a[j+1]=a[j],b[j+1]=b[j];  
 94         a[i+1].clear();  
 95         b[i+1].clear();  
 96         for(int j=B;j<2*B;j++) 
 97           a[i+1].push_back(a[i][j]),b[i+1].push_back(a[i][j]);  
 98         a[i].erase(a[i].begin()+B,a[i].end());  
 99         b[i].clear(); 
100         for(int j=0;j<B;j++)  b[i].push_back(a[i][j]);  
101         sort(b[i].begin(),b[i].end()); 
102         sort(b[i+1].begin(),b[i+1].end());  
103         sum++;   
104       }
105     }  
106   }
107   return 0; 
108 }
View Code

 

方法2:替罪羊树套权值线段树,重构的时候还写了一波线段树合并(感觉不写线段树合并也没事,这里合并的时候节点不能共用,因为要修改),空间无限大,还需要空间回收。  

求答案的时候二分查找, 每个询问需要$(logn*logn)$,总的时间复杂度$O(n*logn*logn)$,但是常数很大,还不如分块来的块。 

  1 #include<bits/stdc++.h>
  2 using namespace std;  
  3 int const N=70000;  
  4 int const M=20000000;  
  5 int sz[N<<1],lc[N<<1],rc[N<<1],n,m,lch[M],rch[M],size[M],rt[N<<1],root,val[N<<1];   
  6 int a[N],b[N],c[N],top,top2,st[N<<1],st2[M];  
  7 void  merge(int &x,int x1,int x2,int l,int r){
  8     if(!x1 && !x2) return;   
  9     x=st2[top2--];  
 10     size[x]=size[x1]+size[x2];   
 11     int mid=(l+r)/2;  
 12     merge(lch[x],lch[x1],lch[x2],l,mid);  
 13     merge(rch[x],rch[x1],rch[x2],mid+1,r);  
 14 }
 15 void insert(int &x,int l,int r,int v,int t){
 16     if(!x) x=st2[top2--];    
 17     if(l==r){
 18         size[x]+=t;  
 19         return;  
 20     }
 21     int mid=(l+r)/2;                                                                                                                                                                                                                                                                                                           
 22     if(v<=mid) insert(lch[x],l,mid,v,t);  
 23     else insert(rch[x],mid+1,r,v,t);  
 24     size[x]=size[lch[x]]+size[rch[x]];  
 25 } 
 26 void build(int &x,int l,int r){
 27     if(l>r) return;  
 28     if(!x) x=st[top--];    
 29     int mid=(l+r)/2;   
 30     val[x]=a[mid];  
 31     build(lc[x],l,mid-1);  
 32     build(rc[x],mid+1,r);  
 33     sz[x]=1+sz[lc[x]]+sz[rc[x]];   
 34     merge(rt[x],rt[lc[x]],rt[rc[x]],0,N); 
 35     insert(rt[x],0,N,a[mid],1);    
 36 }
 37 int del(int x,int k,int v){
 38     int num=sz[lc[x]];  
 39     if(num+1==k){
 40         insert(rt[x],0,N,val[x],-1); 
 41         insert(rt[x],0,N,v,1);  
 42         int t=val[x];  
 43         val[x]=v;   
 44         return t;  
 45     }else {
 46         int t;  
 47         if(num>=k)  t=del(lc[x],k,v);  
 48         else t=del(rc[x],k-num-1,v);   
 49         insert(rt[x],0,N,t,-1); 
 50         insert(rt[x],0,N,v,1);    
 51         return t;   
 52     }
 53 }
 54 void dfs2(int x,int l,int r){
 55     if(!x) return ; 
 56     st2[++top2]=x;  
 57     int mid=(l+r)/2; 
 58     dfs2(lch[x],l,mid);  
 59     dfs2(rch[x],mid+1,r);  
 60     lch[x]=rch[x]=size[x]=0;  
 61 }
 62 void dfs(int x){
 63     if(!x) return ;  
 64     dfs2(rt[x],0,N);  
 65     dfs(lc[x]);  
 66     a[++a[0]]=val[x];  
 67     st[++top]=x;  
 68     dfs(rc[x]);  
 69     lc[x]=rc[x]=rt[x]=sz[x]=val[x]=0;  
 70 }
 71 void rebuild(int &x){
 72     a[0]=0;  
 73     dfs(x);
 74     int t=0;    
 75     build(t,1,a[0]); 
 76     x=t;  
 77 }
 78 void add(int &x,int k,int v){    
 79     if(!x) {
 80         x=st[top--];  
 81         val[x]=v;  
 82         sz[x]=1;  
 83         insert(rt[x],0,N,v,1);  
 84         return;   
 85     }  
 86     int num=sz[lc[x]];  
 87     insert(rt[x],0,N,v,1);  
 88     if(num>=k) add(lc[x],k,v); 
 89     else add(rc[x],k-num-1,v); 
 90     sz[x]=sz[lc[x]]+sz[rc[x]]+1;   
 91     if(max(sz[lc[x]],sz[rc[x]])>0.66*sz[x])rebuild(x); 
 92 }
 93 void get(int x,int l,int r,int ll,int rr){
 94     if(l>r) return;  
 95     if(ll<=l && r<=rr) {
 96         b[++b[0]]=rt[x];    
 97         return;  
 98     }
 99     int mid=l+sz[lc[x]]-1;  
100     if(mid+1>=ll && mid+1<=rr) 
101     {
102         c[++c[0]]=val[x];  
103     }
104     if(ll<=mid) get(lc[x],l,mid,ll,rr);  
105     if(rr>=mid+2) get(rc[x],mid+2,r,ll,rr);   
106 }
107 int main(){
108     scanf("%d",&n);  
109     for(int i=1;i<=n;i++){
110         scanf("%d",&a[i]);    
111     }
112     top=100000;  
113     top2=M-1;  
114     for(int i=1;i<=top;i++) st[i]=top-i+1; 
115     for(int i=1;i<=top2;i++)st2[i]=top2-i+1; 
116     build(root,1,n);  
117     scanf("%d",&m);  
118     int last=0;  
119     while (m--){
120         char s[2];  
121         scanf("%s",s); 
122         if(s[0]=='M') {
123             int x,y;  
124             scanf("%d%d",&x,&y);  
125             x^=last; y^=last;  
126             del(root,x,y);  
127         }
128         if(s[0]=='I'){
129             int x,y;  
130             scanf("%d%d",&x,&y); 
131             x^=last; y^=last;   
132             add(root,x-1,y);      
133             n++;  
134         }
135         if(s[0]=='Q'){   
136             int x,y,k;  
137             scanf("%d%d%d",&x,&y,&k);  
138             x^=last;y^=last; k^=last;  
139             b[0]=c[0]=0;  
140             get(root,1,n,x,y);   
141             int l=0,r=N;  
142             while (l<r){
143                 int mid=(l+r)/2; 
144                 int ts=0;   
145                 for(int i=1;i<=c[0];i++) if(c[i]>=l && c[i]<=mid) ts++;
146                 for(int i=1;i<=b[0];i++) ts+=size[lch[b[i]]];
147                 if(ts>=k) {
148                     for(int i=1;i<=b[0];i++) b[i]=lch[b[i]];  
149                     r=mid;  
150                 }else {
151                     for(int i=1;i<=b[0];i++) b[i]=rch[b[i]];  
152                     k-=ts; 
153                     l=mid+1;  
154                 }        
155             }
156             printf("%d\n",last=l);  
157         }
158     }
159     return 0; 
160 }
View Code

 

 
posted @ 2019-08-18 23:40  zjxxcn  阅读(228)  评论(0编辑  收藏  举报