Dynamic Rankings代码

主要是记录一下整体二分的板子

#include <cstdio>
#include <algorithm>
using namespace std;

#define MAXN 100000

struct element {//修改
	int loc;
	int time;//时间戳
	int value;
	int com;
	element (){}
	element (int loc1, int time1, int value1, int com1) {
		loc = loc1;
		time = time1;
		value = value1;
		com = com1;
	}
}se[MAXN * 3 + 5], teme[MAXN * 3 + 5];
int End = 0;
struct question {//询问
	int num;
	int l, r;
	int k;
	int time;//时间戳
	question (){}
	question (int num1, int l1, int r1, int k1, int time1) {
		num = num1;
		l = l1;
		r = r1;
		k = k1;
		time = time1;
	}
}sq[MAXN + 5], temq[MAXN + 5];
int num = 0;
bool vis[MAXN + 5];
int BIT[MAXN + 5];//单点修改, 区间查询通过BIT来实现
int snow[MAXN + 5];//每次修改需要先删除这个位置上一次的值, 再添加新的值, 所以用一个数组存
int answer[MAXN + 5];//答案

int lowbit (int i) {
	return i & (-i);
}

void change (int l, int v) {
	for (int i = l; i <= MAXN; i += lowbit (i)) {
		BIT[i] += v;
	}
}
int Sum (int l){
	int ans = 0;
	
	for (int i = l; i; i ^= lowbit (i)) {
		ans += BIT[i];
	}
	
	return ans;
}
int ask (int l, int r) {
	return Sum (r) - Sum (l - 1);
}

void dichotomy (int le, int re, int lq, int rq, int vl, int vr) {
	if (vl == vr) {//如果二分到底了, 就直接是答案了
		for (int i = lq; i <= rq; i ++) {
			answer[sq[i].num] = vl;
		}
		
		return ;
	}
	
	int mid = (vl + vr) >> 1;
	int ie = le, iq = lq;
	
	for (int i = lq; i <= rq; i ++) {//相当于普通二分中check的0, 1
		vis[i] = 0;
	}
	while (ie <= re && iq <= rq) {
		if (se[ie].time <= sq[iq].time) {//时间戳来判断操作先后
			change (se[ie].loc, (se[ie].value <= mid) * se[ie].com);
			ie ++;
		}
		else {
			int sum = ask (sq[iq].l, sq[iq].r);
			
			vis[iq] = (sum >= sq[iq].k);
			if (!vis[iq]) {
				sq[iq].k -= sum;//分到mid右边后要将左边修改的贡献提前算上好
			}
			iq ++;
		}
	}
	while (iq <= rq) {
		int sum = ask (sq[iq].l, sq[iq].r);
		
		vis[iq] = (sum >= sq[iq].k);
		if (!vis[iq]) {
			sq[iq].k -= sum;
		}
		iq ++;
	}
	for (int i = le; i < ie; i ++) {//将BIT清0
		change (se[i].loc, -(se[i].value <= mid) * se[i].com);
	}
	//将询问和修改都按照mid分为左右两边
	int ne = le - 1;
	
	for (int i = le; i <= re; i ++) {
		if (se[i].value <= mid) {
			teme[++ ne] = se[i];
		}
	}
	for (int i = le, j = ne; i <= re; i ++) {
		if (se[i].value > mid) {
			teme[++ j] = se[i];
		}
	}
	for (int i = le; i <= re; i ++) {
		se[i] = teme[i];
	}
	
	int nq = lq - 1;
	
	for (int i = lq; i <= rq; i ++) {
		if (vis[i]) {
			temq[++ nq] = sq[i];
		}
	}
	for (int i = lq, j = nq; i <= rq; i ++) {
		if (!vis[i]) {
			temq[++ j] = sq[i];
		}
	}
	for (int i = lq; i <= rq; i ++) {
		sq[i] = temq[i];
	}
	if (nq >= lq) {
		dichotomy (le, ne, lq, nq, vl, mid);
	}
	if (nq < rq) {
		dichotomy (ne + 1, re, nq + 1, rq, mid + 1, vr);
	}
}

int main () {
	int n, m;
	
	scanf ("%d %d", &n, &m);
	for (int i = 1; i <= n; i ++) {
		scanf ("%d", &snow[i]);
		se[++End] = element (i, 0, snow[i], 1);
	}
	for (int i = 1; i <= m; i ++) {
		char opt = getchar ();
		
		while (opt > 'Z' || opt < 'A') {
			opt = getchar ();
		}
		if (opt == 'Q') {
			int l, r, k;
			
			scanf ("%d %d %d", &l, &r, &k);
			++num;
			sq[num] = question (num, l, r, k, i);
		}
		else if (opt == 'C') {
			int l;
			int v;
			
			scanf ("%d %d", &l, &v);
			se[++End] = element (l, i, snow[l], -1);
			snow[l] = v;
			se[++End] = element (l, i, snow[l], 1);
		}
	};
	dichotomy (1, End, 1, num, 0, 1e9);
	for (int i = 1; i <= num; i ++) {
		printf ("%d\n", answer[i]);
	}
}
posted @ 2022-02-17 22:08  小篪篪  阅读(37)  评论(0)    收藏  举报
Live2D