總體二分&cdq分治 ZOJ 2112 Dynamic Rankings

題目:單點更新查詢區間第k大數組

 


按照主席樹的思想,要主席樹套樹狀數組。即按照每一個節點創建主席樹,而後利用樹狀數組的方法來更新維護前綴和。然而,這樣的作法在實際中並不能AC,緣由即卡空間。spa

 


所以咱們採用一種叫作總體二分的方法。code

 


說一下具體作法:get

首先要離線處理博客

咱們把原數列也當成單點更新的操做,而更改值咱們則當作兩個操做,第一個是刪掉原來位置的值,第二個是把新的值放置在這個位置,這樣一來咱們就能夠獲得最長n*3的操做序列。string

而後就是咱們的總體二分步驟了,首先咱們對答案進行二分,這時咱們會得到一個mid值。此時對於某個詢問,若是咱們發如今區間內不大於mid的值的個數少於k的時候,咱們顯然要在比mid大的區間進行二分查找答案,然而咱們此次的查找怎麼辦呢?答案就是記錄下來。咱們發如今比mid大的區間查找答案的時候,咱們以前此次的查找必然也會對下次的查找作出一樣的貢獻,所以咱們只要把此次查找的結果存下來,下次就能夠避免重複查找。而另一種狀況,就不大於mid的值的個數大於等於k的時候,咱們顯然就須要在比mid小的區間進行查找啦,此時咱們以前的查找信息只能做廢。it


聽說總體二分的時間複雜度和詢問的長度是線性相關的,然而我卻認爲是nlogn的,這裏還不太懂,但願有大神解答...io


ZOJ 2112 Dynamic Rankings連接以下:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112
class


此題卡主席樹的空間,可是用此代碼結果以下:方法




代碼以下:

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 1000000000

using namespace std;

int T, n, m, tot, cnt;
int a[50010], ans[10010], tree[50010], cur[70010];
char str[5];

void updata(int pos, int val) {
	while (pos <= n) {
		tree[pos] += val;
		pos += pos & (-pos);
	}
}

int read(int pos) {
	int tmp = 0;
	while (pos > 0) {
		tmp += tree[pos];
		pos -= pos & (-pos);
	}
	return tmp;
}

struct N {
	int l, r, k, id, cur, tp;
	N() {}
	N(int _l, int _r, int _k, int _id, int _cur, int _tp):
		l(_l), r(_r), k(_k), id(_id), cur(_cur), tp(_tp) {}
};
N q[70010], q1[70010], q2[70010];

void ask(int fro, int las, int l, int r) {
	if (fro > las) return ;
	if (l == r) {
		for (int i = fro; i <= las; i++) {
			if (q[i].tp == 3) ans[q[i].id] = l;
		}
		return ;
	}
	int mid = (l + r) / 2;
	for (int i = fro; i <= las; i++) {
		if (q[i].tp == 1 && q[i].k <= mid) updata(q[i].l, 1);
		else if (q[i].tp == 2 && q[i].k <= mid) updata(q[i].l, -1);
		else if (q[i].tp == 3) cur[i] = read(q[i].r) - read(q[i].l - 1);
	}
	for (int i = fro; i <= las; i++) {
		if (q[i].tp == 1 && q[i].k <= mid) updata(q[i].l, -1);
		else if (q[i].tp == 2 && q[i].k <= mid) updata(q[i].l, 1);
	}
	int t1 = 0, t2 = 0;
	for (int i = fro; i <= las; i++) {
		if (q[i].tp == 3) {
			if (q[i].cur + cur[i] >= q[i].k) {
				q1[t1++] = q[i];
			}
			else {
				q[i].cur += cur[i];
				q2[t2++] = q[i];
			}
		}
		else {
			if (q[i].k <= mid) q1[t1++] = q[i];
			else q2[t2++] = q[i];
		}
	}
	for (int i = 0; i < t1; i++) q[fro + i] = q1[i];
	for (int i = 0; i < t2; i++) q[fro + t1 + i] = q2[i];
	ask(fro, fro + t1 - 1, l, mid);
	ask(fro + t1, las, mid + 1, r);
}

int main() {
	//freopen("in.in", "r", stdin);
	//freopen("out.out", "w", stdout);
	scanf("%d", &T);
	while (T--) {
		memset(tree, 0, sizeof(tree));
		scanf("%d %d", &n, &m);
		tot = cnt = 0;
		for (int i = 1; i <= n; i++) {
			scanf("%d", &a[i]);
			q[tot++] = N(i, i, a[i], 0, 0, 1);
		}
		int l, r, k;
		for (int i = 0; i < m; i++) {
			scanf("%s", str);
			if (str[0] == 'Q') {
				scanf("%d %d %d", &l, &r, &k);
				q[tot++] = N(l, r, k, ++cnt, 0, 3);
			}
			else {
				scanf("%d %d", &l, &k);
				q[tot++] = N(l, l, a[l], 0, 0, 2);
				q[tot++] = N(l, l, k, 0, 0, 1);
				a[l] = k;
			}
		}
		//printf("tot = %d cnt = %d\n", tot, cnt);
		ask(0, tot - 1, 0, inf);
		for (int i = 1; i <= cnt; i++)
			printf("%d\n", ans[i]);
	}
	return 0;
}


 

最後,爲神馬csdn沒有發首頁的功能了呢,醬紫個人博客誰來看啊大哭

相關文章
相關標籤/搜索