【洛谷P2617】Dynamic Rankings(整体二分)

题目链接

这是一个动态区间第k大的模板题,主要有两种方法:

  1. 在线: 主席树套树状数组
  2. 离线: 整体二分(更方便)

整体二分的题通常需要满足如下条件:

  1. 单组询问可以二分
  2. 存在高效的数据结构维护修改对询问的影响(像区间修改就不存在)
  3. 题目可以离线做(废话)

对于该题来说,每个询问都可以二分答案,而每次修改的影响也可以利用树状数组维护前缀和的方式实现。

具体做法如下:

  1. 读入并按时间顺序保存所有加点、删点操作和询问操作
  2. 分治:(ql,qr)为操作的区间,(l,r)为答案区间
    当l=r时,所有询问答案为l。
    否则,按时间顺序遍历所有操作,并用树状数组维护[l,mid]范围内的数有多少个。
    对于加点、删点操作,直接修改树状数组;
    对于询问操作,当答案<=mid时把询问放到子任务[l,mid],否则放到子任务[mid+1,r]。
    所有操作分配完成后,撤回树状数组的修改操作,向下递归。

代码:

#include<bits/stdc++.h>
#define N 100005
#define inf 0x3fffffff
#define rep(i, l, r) for(int i=l; i<=r; ++i)
using namespace std;
int n, m;
int a[N]; // numbers
struct que{ // operations
	int t; // time
	int opt; // 0-insert, 1-delete, 2-query
	int l, r; // range
	int k; // 0-value, 2-rank
}q[N*3], L[N*3], R[N*3];
int cnt;
int ans[N];
int cnt1=0, cnt2=0;
namespace bit{ // binary index tree
	int b[N];
	void add(int pos, int val){
		for(int i=pos; i<=n; i+=i&-i) b[i]+=val; 
	}
	int query(int pos){
		int sum=0;
		for(int i=pos; i; i-=i&-i) sum+=b[i];
		return sum;
	}
}
void solve(int ql, int qr, int l, int r){
	//printf("%d %d  %d %d\n", ql, qr, l, r);
	if(l==r){
		for(int i=ql; i<=qr; ++i) if(q[i].opt==2) ans[q[i].t]=l;
		return;
	}
	int mid=(l+r)/2, cntL=0, cntR=0, tmp;
	rep(i, ql, qr){
		if(q[i].opt==0){ // insert
			if(q[i].k<=mid) L[++cntL]=q[i], bit::add(q[i].l, 1);
			else R[++cntR]=q[i];
			
		}
		else if(q[i].opt==1){ // delete
			if(q[i].k<=mid) L[++cntL]=q[i], bit::add(q[i].l, -1);
			else R[++cntR]=q[i];
		}
		else{ // query
			tmp=bit::query(q[i].r)-bit::query(q[i].l-1);
			//printf(" 2:%d %d %d  %d %d\n",q[i].l,q[i].r,q[i].k,mid, tmp);
			if(tmp<q[i].k) q[i].k-=tmp, R[++cntR]=q[i];
			else L[++cntL]=q[i];
		}
	}
	rep(i, 1, cntL){ // recall
		q[ql+i-1]=L[i];
		if(L[i].opt==0) bit::add(L[i].l, -1);
		else if(L[i].opt==1) bit::add(L[i].l, 1);
	}
	rep(i, 1, cntR){
		q[ql+cntL+i-1]=R[i]; // in order of time
	}
	if(cntL) solve(ql, ql+cntL-1, l, mid);
	if(cntR) solve(ql+cntL, qr, mid+1, r);
}
int main(){
	scanf("%d%d", &n, &m);
	rep(i, 1, n){
		scanf("%d", &a[i]);
		q[++cnt]=(que){0, 0, i, i, a[i]}; // insert
	} 
	rep(i, 1, m){
		char s[2];
		scanf("%s", s);
		if(s[0]=='C'){ // change
			++cnt1;
			int x, y;
			scanf("%d%d", &x, &y);
			q[++cnt]=(que){cnt1, 1, x, x, a[x]}; // delete
			q[++cnt]=(que){cnt1, 0, x, x, y}; // insert
			a[x]=y;
		}
		if(s[0]=='Q'){ // query
			++cnt2;
			int l, r, k;
			scanf("%d%d%d", &l, &r, &k);
			q[++cnt]=(que){cnt2, 2, l, r, k}; // query
		}
	}
	solve(1, cnt, 0, inf);
	rep(i, 1, cnt2) printf("%d\n", ans[i]);
	return 0;
} 
全部评论

相关推荐

点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
03-28 13:48
hory权:校招vip纯神人了,还说自己是什么师范大学的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务