【洛谷P2617】Dynamic Rankings

题目

题目链接:https://www.luogu.com.cn/problem/P2617
给定一个含有 \(n\) 个数的序列 \(a_1,a_2 \dots a_n\),需要支持两种操作:

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

思路

经典动态区间第 \(k\) 大问题。我们在做静态区间第 \(k\) 大的问题时,利用类似前缀和的思想求出一个区间值域位于 \([l,r]\) 的数字有多少个。然后为了节省空间将权值线段树“合并”为主席树。
在动态区间第 \(k\) 大的问题中,我们无法再用主席树的方法求前缀和,考虑用树状数组求前缀和,这样每次求 \(log n\) 棵线段树的和。
时间复杂度 \(O(n\log^2 n)\),空间复杂度 \(O(n\log n)\)

代码

#include 
using namespace std;

const int N=200010,LG=20;
int n,m,tot,cnt1,cnt2,a[N],b[N],rt[N],q1[LG],q2[LG];
char ch;

struct Query
{
	int l,r,k,opt;
}ask[N];

struct SegTree
{
	int tot,lc[N*4*LG],rc[N*4*LG],size[N*4*LG];
	
	int update(int x,int l,int r,int k,int val)
	{
		if (!x) x=++tot;
		if (l==k && r==k)
		{
			size[x]+=val;
			return x;
		}
		int mid=(l+r)>>1;
		if (k<=mid) lc[x]=update(lc[x],l,mid,k,val);
			else rc[x]=update(rc[x],mid+1,r,k,val);
		size[x]=size[lc[x]]+size[rc[x]];
		return x;
	}
	
	int query(int l,int r,int k)
	{
		if (l==r) return l;
		int mid=(l+r)>>1,sum=0;
		for (int i=1;i<=cnt1;i++) sum-=size[lc[q1[i]]];
		for (int i=1;i<=cnt2;i++) sum+=size[lc[q2[i]]];
		if (sum

你可能感兴趣的:(【洛谷P2617】Dynamic Rankings)