P2617 Dynamic Rankings

前置知识:整体二分

这道题在整体二分模版题的基础上又增加了一个单点的修改,实际上很简单,既然是单点修改那么就在查的时候改就行了。
具体怎么改呢?比如维护数量的树状数组里 b i t [ x ] bit[x] bit[x]的值为 1 1 1,但是我们有一个修改操作要将 x x x改为 y y y,所以可以考虑以下方法:
1,因为值 x x x被改动了,所以原来关于 x x x的一切值就废了,所以就将树状数组中 b i t [ x ] bit[x] bit[x]的值加上 − b i t [ x ] -bit[x] bit[x],然后就可以把他的值消掉嘞。
2,接着,要把 x x x改为 y y y,再将树状数组中 b i t [ y ] bit[y] bit[y]的值加上 b i t [ x ] bit[x] bit[x]

#include<bits/stdc++.h>
#define xx x&-x
using namespace std;
const int N=1e6+5;
const int M=1e3+5;
int n,m;
struct node{
	int l,r,k,id,op;
}a[N],ql[N],qr[N];
int answer[N];
int bit[N];
int cnt;
void change(int x,int p){
	while(x<=cnt){
		bit[x]+=p;
		x+=xx;
	}
}
int query(int x){
	int res=0;
	while(x){
		res+=bit[x];
		x-=xx;
	}
	return res;
}
void f(int l,int r,int N,int M){
	if(N>=M)return;
	if(l==r){
		for(int i=N;i<=M;i++){
			if(a[i].op==2)answer[a[i].id]=r;
		}
		return;
	}
	int mid=l+r>>1;
	int t1=0,t2=0;
	for(int i=N;i<=M;i++){
		if(a[i].op==1){
			if(mid>=a[i].l){
				ql[++t1]=a[i];
				change(a[i].id,a[i].k);//a[i].k存储了是删除还是增加
			}
			else{
				qr[++t2]=a[i];
			}
		}
		else{
			int x=query(a[i].r)-query(a[i].l-1);
			if(x>=a[i].k){
				ql[++t1]=a[i];
			}
			else{
				a[i].k-=x;
				qr[++t2]=a[i];
			}
		}
	}
	for(int i=1;i<=t1;i++){
		a[i+N-1]=ql[i];
		if(ql[i].op==1)change(ql[i].id,-ql[i].k);//与上面同理
	}
	for(int i=1;i<=t2;i++){
		a[i+N+t1-1]=qr[i];
	}
	f(l,mid,N,N+t1-1);
	f(mid+1,r,N+t1,M);
}
int p[N];
int idx;
signed main(){
	ios::sync_with_stdio(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i].l;
		a[i].id=i;
		a[i].op=1;
		a[i].k=1;
		p[i]=a[i].l;
	}
	cnt=n;
	for(int i=1;i<=m;i++){
		cnt++;
		char op;
		cin>>op;
		if(op=='Q'){
			cin>>a[cnt].l>>a[cnt].r>>a[cnt].k;
			a[cnt].id=++idx;
			a[cnt].op=2;
		}
		else{
			int l,r;
			cin>>l>>r;
			a[cnt]=node{p[l],0,-1,a[l].id,1};//清除
			p[l]=r;
			a[++cnt]=node{p[l],0,1,a[l].id,1};//增加
		}
	}
	f(-1e9,1e9,1,cnt);
	for(int i=1;i<=idx;i++)cout<<answer[i]<<'\n';
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值