BZOJ 3065 带插入区间K小值(sag套线段树)
3065: 带插入区间K小值
Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 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 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
转自大神: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\n",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