P2617-树状数组套主席树

P2617

题目描述

题目描述

题解

树状数组套主席树,离散化数组记得多开几倍(调了一周)
思想其实很简单,就是 l o g n logn logn个主席树一起修改,询问

代码

#include<bits/stdc++.h>
#define M 200010
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
struct tree{int l,r,sum;}tr[M*200];
struct data{int vis,l,r,k,pos,val;}q[M];
int n,m,tmp1[100],tmp2[100],cnt,cnt1,cnt2,rt[M],len,a[M],b[M],tot;
char s[10];
void update(int &k,int l,int r,int pos,int val){
	if(!k) k=++cnt;tr[k].sum+=val;
	if(l==r){return;}
	int mid=(l+r)>>1;
	if(pos<=mid) update(tr[k].l,l,mid,pos,val);
	else update(tr[k].r,mid+1,r,pos,val);
	//tr[k].sum=tr[tr[k].l].sum+tr[tr[k].r].sum;
}
int solve(int l,int r,int k){
	if(l==r)return l;
	int mid=(l+r)>>1,lsize=0;
	for(int i=1;i<=cnt1;i++)lsize+=tr[tr[tmp1[i]].l].sum;
	for(int i=1;i<=cnt2;i++)lsize-=tr[tr[tmp2[i]].l].sum;
	if(k<=lsize){
		for(int i=1;i<=cnt1;i++)tmp1[i]=tr[tmp1[i]].l;
		for(int i=1;i<=cnt2;i++)tmp2[i]=tr[tmp2[i]].l;
		return solve(l,mid,k);
	}else{
		for(int i=1;i<=cnt1;i++)tmp1[i]=tr[tmp1[i]].r;
		for(int i=1;i<=cnt2;i++)tmp2[i]=tr[tmp2[i]].r;
		return solve(mid+1,r,k-lsize);
	}
}
int lowbit(int x){return x&(-x);}
int query(int l,int r,int k){
	memset(tmp1,0,sizeof(tmp1));
	memset(tmp2,0,sizeof(tmp2));
	cnt1=cnt2=0;
	for(int i=r;i;i-=lowbit(i)) tmp1[++cnt1]=rt[i];
	for(int i=l-1;i;i-=lowbit(i)) tmp2[++cnt2]=rt[i];
	return solve(1,len,k);
}
void add(int x,int val){
	int pos=lower_bound(b+1,b+len+1,a[x])-b;
	for(int i=x;i<=n;i+=lowbit(i)) update(rt[i],1,len,pos,val);
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++) b[++tot]=a[i]=read();
	for(int i=1;i<=m;i++){
		scanf("%s",s);
		if(s[0]=='Q') q[i].vis=1,q[i].l=read(),q[i].r=read(),q[i].k=read();
		else q[i].vis=0,q[i].pos=read(),q[i].val=b[++tot]=read();
	}sort(b+1,b+tot+1);
	len=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=n;i++) add(i,1); 
	for(int i=1;i<=m;i++){
		if(!q[i].vis){
			add(q[i].pos,-1);
			a[q[i].pos]=q[i].val;
			add(q[i].pos,1); 
		}else printf("%d\n",b[query(q[i].l,q[i].r,q[i].k)]);
	}return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
树状数组是一种用于加速前缀和操作的数据结构。它可以在O(logn)的时间复杂度内更新单个元素,并且可以在O(logn)的时间复杂度内查询一个区间的和。\[1\] 树状数组的基本思想是将数组分解成若干个长度为2的幂次的区间,每个区间的和都可以通过一系列区间和的累加得到。树状数组的每个节点都存储了一段区间的和,通过不断迭代lowbit()运算,可以得到从1到x之间的和。\[3\] 在树状数组的实现中,可以使用add()函数来更新单个元素的值,使用query()函数来查询一个区间的和。add()函数通过迭代lowbit()运算,将更新的值加到对应的节点上。query()函数通过计算两个前缀和的差值来得到一个区间的和。\[2\] 差分树状数组树状数组的一种变体,它可以用来求解区间最大值。差分树状数组的基本思想是将原始数组转化为差分数组,然后对差分数组建立树状数组。通过查询树状数组得到的前缀和,再加上差分数组的前缀和,就可以得到原始数组的区间最大值。\[2\] 综上所述,树状数组是一种用于加速前缀和操作的数据结构,可以在O(logn)的时间复杂度内更新单个元素和查询一个区间的和。差分树状数组树状数组的一种变体,用于求解区间最大值。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* *3* [RMQ问题--------树状数组](https://blog.csdn.net/weixin_43743711/article/details/107191842)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值