序列操作IV
题目描述
给出序列 a1,a2,…,an(0≤ai≤109),有关序列的两种操作。
1. ai(1≤i≤n)变成 x(0≤x≤109)。
2. 求 al,al+1,…,ar(1≤l≤r≤n)第 k(1≤k≤r-l+1)小。
输入格式
第一行包含两个数 n(1≤n≤2×104)和 m(1≤m≤2×104),表示序列长度和操作次数。
接下来一行 n 个数,以空格隔开,表示 a1,a2,…,an 。
接下来m行,每行为以下两种格式之一:
- 0 i x , 表示 ai=x。
- 1 l r k ,求 al,al+1,…,ar 的第 k 小。
输出格式
对于每次询问,输出单独的一行表示答案。
样例数据 1
输入 [复制]
5 3
1 2 3 4 5
1 1 5 3
0 3 5
1 1 5 3
输出
3
4
解析:
线段树套平衡树。
如果用线段树会碰到一个问题,就是线段树无法查询第K小,这时候就需要再套一个平衡树计算第K小,当然直接找是不现实的,因为平衡树不支持合并,所以这时候需要再二分这个值,带入验证即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int Max=20010;
int n,m,tot;
int num[Max],tree[Max<<2];
struct shu{int l,r,size,cnt,data,val;};
shu a[Max<<5];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') {f=-1;c=getchar();}
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline int NEW(int val)
{
a[++tot].val = val;
a[tot].cnt = a[tot].size = 1;
a[tot].data = rand();
return tot;
}
inline void update(int p){a[p].size = a[a[p].l].size + a[a[p].r].size + a[p].cnt;}
inline void zig(int &p)
{
int q = a[p].l;
a[p].l=a[q].r,a[q].r=p,p=q;
update(a[p].r),update(p);
}
inline void zag(int &p)
{
int q=a[p].r;
a[p].r=a[q].l,a[q].l=p,p=q;
update(a[p].l),update(p);
}
inline void Insert(int &p,int val)
{
if(!p) {p = NEW(val);return;}
if(a[p].val == val){a[p].cnt++,update(p);return;}
if(a[p].val > val)
{
Insert(a[p].l,val);
if(a[a[p].l].data > a[p].data) zig(p);
}
if(a[p].val < val)
{
Insert(a[p].r,val);
if(a[a[p].r].data > a[p].data) zag(p);
}
update(p);
}
inline void Remove(int &p,int val)
{
if(!p) return;
if(a[p].val == val)
{
if(a[p].cnt > 1)
{
a[p].cnt--,update(p);
return;
}
if(a[p].l || a[p].r)
{
if(!a[p].r || a[a[p].l].data > a[a[p].r].data) zig(p),Remove(a[p].r,val);
else zag(p),Remove(a[p].l,val);
update(p);
}
else p=0;
return;
}
val < a[p].val ? Remove(a[p].l,val) : Remove(a[p].r,val);
update(p);
}
inline int GetRanKByVal(int p,int val)
{
if(!p) return 0;
if(val == a[p].val) return a[a[p].l].size + 1;
if(val < a[p].val) return GetRanKByVal(a[p].l,val);
else return a[a[p].l].size + a[p].cnt + GetRanKByVal(a[p].r,val);
}
inline void build(int root,int l,int r)
{
for(int i=l;i<=r;i++) Insert(tree[root],num[i]);
if(l == r) return;
int mid = l + r >> 1;
build(root<<1,l,mid),build(root<<1|1,mid+1,r);
}
inline void modify(int root,int l,int r,int pos,int x)
{
Remove(tree[root],num[pos]),Insert(tree[root],x);
if(l == r){num[l] = x;return;}
int mid = l + r >> 1;
if(pos <= mid) modify(root<<1,l,mid,pos,x);
else modify(root<<1|1,mid+1,r,pos,x);
}
inline int Q(int root,int l,int r,int L,int R,int num)
{
if(L <= l && R >= r) return GetRanKByVal(tree[root],num);
int mid = l + r >> 1,sum=0;
if(L <= mid) sum += Q(root<<1,l,mid,L,R,num);
if(R > mid) sum += Q(root<<1|1,mid+1,r,L,R,num);
return sum;
}
inline void print(int x)
{
if(x < 0) putchar('-'),x=-x;
if(x > 9) print(x/10);
putchar('0' + x%10);
}
int main()
{
srand(time(0));
n=get_int(),m=get_int();
for(int i=1;i<=n;i++) num[i]=get_int();
build(1,1,n);
for(int i=1;i<=m;i++)
{
int flag=get_int();
if(!flag)
{
int pos=get_int(),x=get_int();
modify(1,1,n,pos,x);
}
else
{
int L=get_int(),R=get_int(),k=get_int(),ans=-1,l=0,r=1e9,mid;
while(l<=r)
{
mid = l + r >> 1;
if(Q(1,1,n,L,R,mid) >= k) ans = mid,r=mid-1;
else l=mid+1;
}
print(ans),putchar('\n');
}
}
return 0;
}