POJ 2104 - 主席树 / 询问莫队+权值分块

传送门

题目大意应该都清楚。
今天看到一篇博客用分块+莫对做了这道题,直接惊呆了。
首先常规地离散化后将询问分块,对于某一询问,将莫队指针移动到指定区间,移动的同时处理权值分块的数字出现次数(单独、整块),莫队完后,现在的权值分块就是关于当前区间的。然后再从左到右扫描分块,直到数字个数+该块个数>=k,这时进入该块逐个加,当数字个数>=k时,直接跳出输出离散化之前的数字。
试了很多种块的大小,最后还是选择sqrt(100000) ≈ 320,时间比我的主席树还少(肯定是我写的丑)。

code

1040ms

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;

const int N = 1e5 + 5, M = 5e3 + 5, S = 320;
int n, m;
int val[N], b[N], len, cnt[S], num_cnt[N], ans[M];
struct QRY{
	int x, y, k, mo_bl, id;
	inline bool operator < (const QRY &b) const{
		return mo_bl < b.mo_bl || (mo_bl == b.mo_bl && y < b.y);
	}
}qry[M];
int head, tail;

namespace IO{
	inline int read(){
		int i = 0, f = 1; char ch = getchar();
		for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
		if(ch == '-') f = -1, ch = getchar();
		for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
		return i * f;
	}
	inline void wr(int x){
		if(x < 0) putchar('-'), x = -x;
		if(x > 9) wr(x / 10);
		putchar(x % 10 + '0');
	}
}using namespace IO;

inline void disc_init(){
	sort(b + 1, b + len + 1);
	len = unique(b + 1, b + len + 1) - b - 1;
	for(int i = 1; i <= n; i++) val[i] = lower_bound(b + 1, b + len + 1, val[i]) - b;
}

inline void handleMo(int l, int r){
	while(head < l){
		int part_bl = val[head] / S + (val[head] % S ? 1 : 0);
		cnt[part_bl]--;
		num_cnt[val[head]]--;
		head++;
	}
	while(head > l){
		head--;
		int part_bl = val[head] / S + (val[head] % S ? 1 : 0);
		cnt[part_bl]++;
		num_cnt[val[head]]++;
	}
	while(tail < r){
		tail++;
		int part_bl = val[tail] / S + (val[tail] % S ? 1 : 0);
		cnt[part_bl]++;
		num_cnt[val[tail]]++;
	}
	while(tail > r){
		int part_bl = val[tail] / S + (val[tail] % S ? 1 : 0);
		cnt[part_bl]--;
		num_cnt[val[tail]]--;
		tail--;
	}
}
int main(){
	freopen("h.in", "r", stdin);
	n = read(), m = read();
	for(int i = 1; i <= n; i++) val[i] = b[++len] = read();
	disc_init();
	for(int i = 1; i <= m; i++){
		int x = read(), y = read(), k = read(), bl = x / S + (x % S ? 1 : 0);
		qry[i] = (QRY){x, y, k, bl, i};
	}
	sort(qry + 1, qry + m + 1);
	head = tail = 0;
	for(int i = 1; i <= m; i++){
		int l = qry[i].x, r = qry[i].y, k = qry[i].k, sum = 0;
		handleMo(l, r);
		int now = 1;
		try{
			while(sum + cnt[now] < k) sum += cnt[now++];
			for(int j = (now - 1) * S + 1; j <= min(n, now * S); j++)
				if(sum + num_cnt[j] < k) sum += num_cnt[j];
				else throw(j);
		}
		catch(int x){
			ans[qry[i].id] = b[x];
			continue;
		}
	}
	for(int i = 1; i <= m; i++) wr(ans[i]), putchar('\n');
	return 0;
}

posted @ 2017-10-12 17:04  CzYoL  阅读(196)  评论(0编辑  收藏  举报