bzoj3524 [Poi2014]Couriers

[Poi2014]Couriers

Time Limit: 20 Sec Memory Limit: 256 MB

Description

给一个长度为n的序列a。1≤a[i]≤n。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。

Input

第一行两个数n,m。
第二行n个数,a[i]。
接下来m行,每行两个数l,r,表示询问[l,r]这个区间。

Output

m行,每行对应一个答案。

Sample Input

7 5

1 1 3 2 3 4 3

1 3

1 4

3 7

1 7

6 6

Sample Output

1

0

3

0

4

HINT

【数据范围】

n,m≤500000


终于学了一波主席树。。。。还是很简单的啦~~
无数个线段树搞前缀和操作233
就是利用很多东西是重复的来优化的啦
贴个板呗~


#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 5, L = 0, R = 1;
struct lpl{
	int size, son[2];
}node[maxn];
int n, m, cnt, root[500005];

void build(int l, int r, int x, int &t, int val)
{
	t = ++cnt;
	node[t] = node[x]; node[t].size++;
	if(l == r) return;
	int mid = (l + r) >> 1;
	if(val <= mid) build(l, mid, node[x].son[L], node[t].son[L], val);
	else build(mid + 1, r, node[x].son[R], node[t].son[R], val);
}

inline int query(int A, int B)
{
	int x = root[A - 1], t = root[B], l = 1, r = n, tmp = (B - A + 1) >> 1;
	while(l < r){
		if(node[t].size - node[x].size <= tmp) return 0;
		int mid = (l + r) >> 1;
		if(node[node[t].son[L]].size - node[node[x].son[L]].size > tmp){
			r = mid; t = node[t].son[L]; x = node[x].son[L];
		}
		else if(node[node[t].son[R]].size - node[node[x].son[R]].size > tmp){
			l = mid + 1; t = node[t].son[R]; x = node[x].son[R];
		}
		else  return 0;
	}
	return l;
}

int main()
{
	int x, y; scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i){
		scanf("%d", &x); 
		build(1, n, root[i - 1], root[i], x);
	} 
	for(int i = 1; i <= m; ++i){
		scanf("%d%d", &x, &y);
		if(x > y) printf("0\n");
		printf("%d\n", query(x, y));
	}
	return 0;
}

posted @ 2018-05-26 15:50  沛霖  阅读(111)  评论(0编辑  收藏  举报