【树套树】序列操作IV

                                                       序列操作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

输出


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;
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/81369099