1. 程式人生 > >牛客練習賽10 E題 數列查找 (分塊思想 + 莫隊算法)

牛客練習賽10 E題 數列查找 (分塊思想 + 莫隊算法)

意義 blog str aps mes blank ref pair rem

題目鏈接 數列查找

考慮分塊然後跑莫隊,

設$c[i]$為$i$在當前維護的區間內出現的次數,

$g[i]$為在當前維護的區間內有多少個數出現次數為$i$,

$bg[i]$把出現次數分塊,$bg[i]$的意義是第$i$個塊代表的所有出現次數中出現的個數。

$f[i][j]$對$1$到$n$分塊,意義為當前在第$j$個數字塊中有多少個數出現次數為$i$。

每一次詢問的時候,我們先求出當前要求的出現次數是多少。

這個通過$bg[]$來求。

然後再根據$f[][]$確定當前區間中出現$k1$次的所有數中第$k2$小的數。

為了方便我用了離散化。

時間復雜度$O(m\sqrt{n} + n\sqrt{n})$

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define MP		make_pair
#define fi		first
#define se		second


typedef long long LL;

const int N = 4e4 + 10;
const int M = 203;

int belong[N];
int c[N], g[N], bg[N];
int f[N][M];
int l, r, kth;
int blocknum;
int L[M], R[M], ret[N];

struct node{
	int l, r, x, y, id;
	void scan(){ scanf("%d%d%d%d", &l, &r, &x, &y); }

	friend bool operator < (const node &a, const node &b){
		return belong[a.l] == belong[b.l] ? a.r < b.r : belong[a.l] < belong[b.l];
	}
} q[N];

int a[N], val[N];
int bs, cnt;
int n, m;


void remove(int x, int y){
	--f[y][belong[x]];
	if (g[y] == 1) --bg[belong[y]];
	--g[y];
}

void add(int x, int y){
	++f[y][belong[x]];
	if (g[y] == 0) ++bg[belong[y]];
	++g[y];
}

int solve(int i){
	int num = 0;
	rep(j, 1, blocknum){
		num += bg[j];
		if (num >= q[i].x){
			num -= bg[j];
			rep(k, L[j], R[j]){
				num += (int)(g[k] > 0);
				if (num == q[i].x) return k;
			}
		}
	}

	return 0;
}

int calc(int i, int x){
	int num = 0;
	rep(j, 1, blocknum){
		num += f[x][j];
		if (num >= q[i].y){
			num -= f[x][j];
			rep(k, L[j], R[j]){
				num += (int)(c[k] == x);
				if (num == q[i].y) return k;
			}
		}
	}

	return 0;
}


int main(){

	scanf("%d", &n);
	rep(i, 1, n) scanf("%d", a + i), val[i] = a[i], q[i].id = i;

	sort(val + 1, val + n + 1);
	cnt = unique(val + 1, val + n + 1) - val - 1;
	rep(i, 1, n) a[i] = lower_bound(val + 1, val + cnt + 1, a[i]) - val;

	bs = sqrt(n);
	rep(i, 1, n) belong[i] = (i - 1) / bs + 1;
	blocknum = belong[n];

	rep(i, 1, blocknum) L[i] = 1e9, R[i] = 0;
	rep(i, 1, n){
		L[belong[i]] = min(L[belong[i]], i);
		R[belong[i]] = max(R[belong[i]], i);
	}

	scanf("%d", &m);
	rep(i, 1, m) q[i].scan();
	sort(q + 1, q + m + 1);

	rep(i, 1, n) add(a[i], 0);
	l = 1, r = 0;

	rep(i, 1, m){
		while (r < q[i].r){
			++r;
			remove(a[r], c[a[r]]);
			++c[a[r]];
			add(a[r], c[a[r]]);
		}

		while (r > q[i].r){
			remove(a[r], c[a[r]]);
			--c[a[r]];
			add(a[r], c[a[r]]);
			--r;
		}

		while (l > q[i].l){
			--l;
			remove(a[l], c[a[l]]);
			++c[a[l]];
			add(a[l], c[a[l]]);
		}

		while (l < q[i].l){
			remove(a[l], c[a[l]]);
			--c[a[l]];
			add(a[l], c[a[l]]);
			++l;
		}

		kth = solve(i);
		ret[q[i].id] = val[calc(i, kth)];


	}

	rep(i, 1, m) printf("%d\n", ret[i]);
	return 0;
}

  

牛客練習賽10 E題 數列查找 (分塊思想 + 莫隊算法)