首页 > 代码库 > Bzoj3065 带插入区间K小值
Bzoj3065 带插入区间K小值
Submit: 3436 Solved: 1103
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 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
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
树 树套树 替罪羊树套权值线段树
非旋转的平衡树是可以套在别的树外面的。
用替罪羊树维护序列,替罪羊树上塞一堆权值线段树维护区间内有哪些值。
查询的时候,把该区间对应的线段树区间都拎出来,一起二分找第k小。
查询方法学自黄学长
注意替罪羊树重建的时候,要按照中序遍历回收节点,能省一个排序操作。
应该用线段树合并来着,然而听说合并写得不够好的话和暴力重建一个速度,那我就直接暴力重建了
刷了一页WA
1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 //const int MXN=10000010; 10 const int mxn=150010; 11 const int MX=70000; 12 int read(){ 13 int x=0,f=1;char ch=getchar(); 14 while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 15 while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 16 return x*f; 17 } 18 struct SGT{ 19 int l,r; 20 int smm; 21 }sg[mxn<<6]; 22 int scnt=0; 23 int st[mxn<<6],top=0; 24 int rot[mxn]; 25 inline int newnode(){ 26 if(top){ 27 int tmp=st[top--]; 28 sg[tmp].l=sg[tmp].r=sg[tmp].smm=0; 29 return tmp; 30 } 31 return ++scnt; 32 } 33 inline void pushup(int rt){ 34 sg[rt].smm=sg[sg[rt].l].smm+sg[sg[rt].r].smm;return; 35 } 36 void del(int &rt){//线段树回收结点 37 if(!rt)return; 38 if(sg[rt].l)del(sg[rt].l); 39 if(sg[rt].r)del(sg[rt].r); 40 st[++top]=rt; rt=0; 41 return; 42 } 43 void update(int v,int p,int l,int r,int &rt){ 44 if(!rt)rt=newnode(); 45 if(l==r){sg[rt].smm+=v;return;} 46 int mid=(l+r)>>1; 47 if(p<=mid)update(v,p,l,mid,sg[rt].l); 48 else update(v,p,mid+1,r,sg[rt].r); 49 pushup(rt); 50 if(!sg[rt].smm)del(rt); 51 return; 52 } 53 // 54 struct node{ 55 int l,r; 56 int val,sz; 57 }t[mxn]; 58 int n,Q; 59 int cnt=0,ROT; 60 int flag=0,fafa=0;//重构标记 61 int w[mxn]; 62 int bnode[mxn],bct=0; 63 int dfn[mxn],dtime=0; 64 void Build(int l,int r,int &rt){ 65 if(l>r){rt=0;return;} 66 if(l==r){ 67 rt=dfn[l]; 68 update(1,t[rt].val,0,MX,rot[rt]); 69 t[rt].sz=1; 70 return; 71 } 72 int mid=(l+r)>>1; 73 rt=dfn[mid]; 74 Build(l,mid-1,t[rt].l); Build(mid+1,r,t[rt].r); 75 for(int i=l;i<=r;i++)//建线段树 76 update(1,t[dfn[i]].val,0,MX,rot[rt]); 77 t[rt].sz=t[t[rt].l].sz+t[t[rt].r].sz+1; 78 return; 79 } 80 void DEL(int &x){//删除替罪羊树结点 81 if(!x)return; 82 del(rot[x]);//删除对应线段树 83 DEL(t[x].l); 84 bnode[++bct]=x;//中序遍历删除 85 DEL(t[x].r); 86 t[x].sz=0; 87 x=0; 88 return; 89 } 90 void Rebuild(int &x){ 91 DEL(x); 92 for(int i=1;i<=bct;i++)dfn[i]=bnode[i]; 93 Build(1,bct,x); 94 bct=0;//clear 95 return; 96 } 97 void insert(int v,int k,int &rt){ 98 if(!rt){ 99 rt=++n;100 t[rt].val=v;101 t[rt].sz=1;102 update(1,t[rt].val,0,MX,rot[rt]);103 return;104 }105 update(1,v,0,MX,rot[rt]);106 /* int L=sg[rot[t[rt].l]].smm;107 if(L>=k)insert(v,k,t[rt].l);108 else insert(v,k-L-1,t[rt].r);*/109 if(t[t[rt].l].sz<k)insert(v,k-t[t[rt].l].sz-1,t[rt].r);110 else insert(v,k,t[rt].l);111 t[rt].sz=t[t[rt].l].sz+t[t[rt].r].sz+1;112 // int R=sg[rot[rt]].smm;113 // if(L/(double)R>0.75 || L/(double)R<0.2)flag=rt;114 if(t[t[rt].l].sz/(double)t[rt].sz>0.72 || t[t[rt].l].sz/(double)t[rt].sz<0.25)flag=rt;115 if(flag==t[rt].l || flag==t[rt].r)fafa=rt;116 return;117 }118 int change(int v,int k,int rt){119 // printf("change:%d %d %d\n",v,k,rt);120 update(1,v,0,MX,rot[rt]);121 int tmp=0;//查找旧值 122 /* int L=sg[rot[t[rt].l]].smm;123 if(L+1==k){tmp=t[rt].val;t[rt].val=v;}124 else if(L>=k)tmp=change(v,k,t[rt].l);125 else tmp=change(v,k-L-1,t[rt].r);*/126 if(t[t[rt].l].sz+1==k){127 tmp=t[rt].val;t[rt].val=v;128 }129 else if(t[t[rt].l].sz>=k)tmp=change(v,k,t[rt].l);130 else tmp=change(v,k-t[t[rt].l].sz-1,t[rt].r);131 update(-1,tmp,0,MX,rot[rt]);//删除旧值 132 return tmp;133 }134 vector<int>qt,qp;//区间 单点 135 void query(int L,int R,int x){//在平衡树上收集区间 136 // if(!x)return;137 int ls=t[x].l,rs=t[x].r;138 int l=sg[rot[ls]].smm,r=sg[rot[x]].smm;139 //当前结点包含区间 140 if(L==1 && R==r){qt.push_back(rot[x]);return;}141 if(L<=l+1 && l+1<=R) qp.push_back(t[x].val);142 if(R<=l)query(L,R,t[x].l);143 else if(L>l+1)query(L-(l+1),R-(l+1),t[x].r);144 else{145 if(L<=l)query(L,l,t[x].l);146 if(r>l+1)query(1,R-l-1,t[x].r);147 }148 return;149 }150 int Query(int L,int R,int K){151 query(L,R,ROT);152 K--;153 int l=0,r=MX,s1=qt.size(),s2=qp.size();154 while(l<r){//二分答案 155 int mid=(l+r)>>1,smm=0;156 for(int i=0;i<s1;i++)smm+=sg[sg[qt[i]].l].smm;//区间 157 for(int i=0;i<s2;i++)//单点 158 if(l<=qp[i] && qp[i]<=mid)smm++;159 if(K<smm){160 for(int i=0;i<s1;i++)qt[i]=sg[qt[i]].l;161 r=mid;162 }163 else{164 for(int i=0;i<s1;i++)qt[i]=sg[qt[i]].r;165 l=mid+1;K-=smm;166 }167 }168 qt.clear();qp.clear();169 return l;170 }171 int lastans=0;172 int main(){173 // freopen("in.txt","r",stdin);174 int i,j;175 n=read();176 for(i=1;i<=n;i++)w[i]=read();177 for(i=1;i<=n;i++)dfn[i]=i,t[i].val=w[i];178 Build(1,n,ROT);179 Q=read();180 char op[2];int x,y,k;181 while(Q--){182 scanf("%s",op);183 switch(op[0]){184 case ‘Q‘:{185 x=read()^lastans;y=read()^lastans;k=read()^lastans;186 // x=read();y=read();k=read();187 lastans=Query(x,y,k);188 printf("%d\n",lastans);189 break;190 }191 case ‘M‘:{192 x=read()^lastans;k=read()^lastans;193 // x=read();k=read();194 change(k,x,ROT);195 break;196 }197 case ‘I‘:{198 x=read()^lastans;k=read()^lastans;199 // x=read();k=read();200 flag=0;fafa=0;201 insert(k,x-1,ROT);202 if(flag){203 if(flag==ROT)Rebuild(ROT);204 else if(t[fafa].l==flag)Rebuild(t[fafa].l);205 else if(t[fafa].r==flag)Rebuild(t[fafa].r);206 }207 break;208 }209 }210 }211 return 0;212 }
Bzoj3065 带插入区间K小值