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;
}
心如花木,向阳而生。