P2617 分块动态区间第K小

Dynamic Rankings

题目描述

给定一个含有 \(n\) 个数的序列 \(a_1,a_2 \dots a_n\),需要支持两种操作:

  • Q l r k 表示查询下标在区间 \([l,r]\) 中的第 \(k\) 小的数
  • C x y 表示将 \(a_x\) 改为 \(y\)

输入格式

第一行两个正整数 \(n,m\),表示序列长度与操作个数。
第二行 \(n\) 个整数,表示 \(a_1,a_2 \dots a_n\)
接下来 \(m\) 行,每行表示一个操作,都为上述两种中的一个。

输出格式

对于每一次询问,输出一行一个整数表示答案。

样例 #1

样例输入 #1

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3

样例输出 #1

3
6

提示

【数据范围】

对于 \(10\%\) 的数据,\(1\le n,m \le 100\)
对于 \(20\%\) 的数据,\(1\le n,m \le 1000\)
对于 \(50\%\) 的数据,\(1\le n,m \le 10^4\)
对于 \(100\%\) 的数据,\(1\le n,m \le 10^5\)\(1 \le l \le r \le n\)\(1 \le k \le r-l+1\)\(1\le x \le n\)\(0 \le a_i,y \le 10^9\)

分块注意细节!!!

#include<bits/stdc++.h>//分块   动态区间第K小问题
using namespace std;
#define int long long
const int N=1e5+5;
int n,m,len,L[N],R[N],pos[N],a[N],b[N],tot;
void blk_sort(int x)//第x块内排序 
{
	for(int i=L[x];i<=R[x];i++)b[i]=a[i];
	sort(b+L[x],b+R[x]+1);
} 
void update(int x,int k)//修改 a[x]=k 
{
	a[x]=k;
	blk_sort(pos[x]);
}
int query(int l,int r,int k)//[l,r]区间中 ≤K の数的个数 
{
	int cnt=0;
	//端点块暴力枚举 中间块利用有序性lower_bound 
	int x=pos[l],y=pos[r];
	if(x==y)
	{
		for(int i=l;i<=r;i++)
			cnt+=(a[i]<=k);
	}
	else
	{
		for(int i=l;i<=R[x];i++)
			cnt+=(a[i]<=k);
		for(int i=L[y];i<=r;i++)
			cnt+=(a[i]<=k);
		for(int i=x+1;i<=y-1;i++)
			cnt+=upper_bound(b+L[i],b+R[i]+1,k)-(b+L[i]-1)-1;
			//第一个-1是因为 类比 (b+1,b+n+1,x)-(b+1-1)
			//第二个-1是因为upper ---> <= 有个-1
	}
	return cnt;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	len=sqrt(n);//预处理 自己手写前几个找规律即可 
	tot=n/len;
	if(n%len!=0)tot++;//tot 块数 
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)pos[i]=(i-1)/len+1;//处理每个i所∈块序数 
	for(int i=1;i<=tot;i++)//处理L[] R[] 
		L[i]=(i-1)*len+1,R[i]=i*len;
	R[tot]=n;// 最后一块不一定完整
	for(int i=1;i<=tot;i++)blk_sort(i);//初始也要有序 
	while(m--)
	{
		char op;
		cin>>op;
		if(op=='Q')
		{
			int l,r,k;
			cin>>l>>r>>k;
			//二分答案
			int L=1,R=1e9,mid,ans;
			while(L<=R)
			{
				mid=(L+R)>>1;
				if(query(l,r,mid)>=k)ans=mid,R=mid-1;//mid处可能为答案 若后面还有满足的就更新 否则说明就是第K小 
				else L=mid+1;//mid处不满足 
			}
			cout<<ans<<"\n";
		}
		else
		{
			int x,y;
			cin>>x>>y;
			update(x,y);
		}
	} 
	return 0;
} 
posted @ 2023-04-17 20:23  N0zoM1z0  阅读(9)  评论(0编辑  收藏  举报