洛谷P2617 Solution

题目链接

题解

动态查询区间k小值——树状数组套主席树( •̀ ω •́ )

如果直接主席树上进行动态修改,每次需要修改([l,r])区间内所有的根,时间复杂度为(O(nlogn))。主席树是前缀和,树状数组也是前缀和,而且还可以动态修改,巧了你们两个认识一下(

具体实现:主席树中以(rt_i)为根的子树存储的不再是第(i)个版本(([1,i]))的信息,而是lowbit区间中版本的信息(如同树状数组中的一个节点)。modify:与树状数组相仿,不过修改循环从(x)开始而非(1)(a_x)的修改仅影响([x,n])的前缀和)。query:预处理出需要查询的主席树根(约(logn)个,以lowbit覆盖查询区间),统计左儿子中元素数量与转移时,预处理的每个根都进行一遍即可。

AC代码

#include<bits/stdc++.h>
#define lowb(x) x&(-x)
using namespace std;
const int N=1e5+10;
struct node {char op; int x,y,z;} q[N];
int rt[N],ls[N*200],rs[N*200],sum[N*200],tmp[2][20],cnt[2];
//tmp[1/0]:[1,r]/[1,l-1]区间内需要查询的根(节点),cnt[2]:需要查询的根数
int a[N],b[2*N],nn,n,tot;//b:离散化数组
void add(int &x,int l,int r,int pos,int v)
{
	if(!x) x=++tot;
	sum[x]+=v;
	if(l==r) return;
	int mid=(l+r)/2;
	if(pos<=mid) add(ls[x],l,mid,pos,v);
	else add(rs[x],mid+1,r,pos,v);
}
void p_add(int x,int v)
{
	int k=lower_bound(b+1,b+nn+1,a[x])-b;//a[x]离散化后的值
	for(int i=x;i<=n;i+=lowb(i)) add(rt[i],1,nn,k,v);
}
int ask(int l,int r,int k)
{
	if(l==r) return l;
	int num=0,mid=(l+r)/2;	
	for(int i=1;i<=cnt[1];i++) num+=sum[ls[tmp[1][i]]];
	for(int i=1;i<=cnt[0];i++) num-=sum[ls[tmp[0][i]]];
	if(k<=num) 
	{
		for(int i=1;i<=cnt[1];i++) tmp[1][i]=ls[tmp[1][i]];
		for(int i=1;i<=cnt[0];i++) tmp[0][i]=ls[tmp[0][i]];
		return ask(l,mid,k);
	}
	for(int i=1;i<=cnt[1];i++) tmp[1][i]=rs[tmp[1][i]];
	for(int i=1;i<=cnt[0];i++) tmp[0][i]=rs[tmp[0][i]];
	return ask(mid+1,r,k-num);//!处理右儿子时k不要忘记-num
}
int p_ask(int l,int r,int k)
{
	memset(tmp,0,sizeof(tmp));
	cnt[0]=cnt[1]=0;	
	for(int i=r;i;i-=lowb(i)) tmp[1][++cnt[1]]=rt[i];
	for(int i=l-1;i;i-=lowb(i)) tmp[0][++cnt[0]]=rt[i];
	return ask(1,nn,k);
}
int main()
{
	ios::sync_with_stdio(0); 
	int m,x,y,z; char op;
	cin>>n>>m;
	for(int i=1;i<=n;i++) {cin>>a[i]; b[++nn]=a[i];}
	for(int i=1;i<=m;i++)
	{
		cin>>q[i].op;
		if(q[i].op=='C') {cin>>q[i].x>>q[i].y; b[++nn]=q[i].y;}
		else cin>>q[i].x>>q[i].y>>q[i].z;
	}
	sort(b+1,b+nn+1); nn=unique(b+1,b+nn+1)-b-1;
	for(int i=1;i<=n;i++) p_add(i,1);
	for(int i=1;i<=m;i++)
	{
		if(q[i].op=='C') 
		{
			p_add(q[i].x,-1); 
			a[q[i].x]=q[i].y; p_add(q[i].x,1);
		}
		else cout<<b[p_ask(q[i].x,q[i].y,q[i].z)]<<endl; 
	}
	return 0;
}
原文地址:https://www.cnblogs.com/violetholmes/p/14729314.html