链接
题目描述
给一个数列,每次询问一个区间内有没有一个数出现次数超过一半
思路
其实很容易想到,这道题就是查询的时候记录一下一个数是否有超过区间长度的一半就可以了
模板修改一丢丢
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct trr
{
int k, ls, rs;
}tr[32000005];
int cnt, n, m;
int p[1000005], a[1000005], T[1000005];
void add(int &x, int last)
{
x = ++cnt;
tr[x] = tr[last];
}
void build(int &x, int l, int r)
{
x = ++cnt;
if(l == r) return;
int mid = (l + r) >> 1;
build(tr[x].ls, l, mid);
build(tr[x].rs, mid + 1, r);
}
void init(int &x, int last, int l, int r, int val)
{
add(x, last);
if(l == r) {
tr[x].k++;
return;
}
int mid = (l + r) >> 1;
if(val <= mid) init(tr[x].ls, tr[last].ls, l, mid, val);
if(val > mid) init(tr[x].rs, tr[last].rs, mid + 1, r, val);
tr[x].k = tr[tr[x].ls].k + tr[tr[x].rs].k;
}
int ask(int u, int v, int l, int r, int go)
{
int mid = (l + r) >> 1;
int x = tr[tr[v].ls].k - tr[tr[u].ls].k;//比1大比mid小
int xx = tr[tr[v].rs].k - tr[tr[u].rs].k;//比mid大比r小
if(l >= r) return l;
if(x > go) return ask(tr[u].ls, tr[v].ls, l, mid, go);
if(xx > go) return ask(tr[u].rs, tr[v].rs, mid + 1, r, go);
return 0;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]), p[i] = a[i];
sort(p + 1, p + n + 1);
int q = unique(p + 1, p + n + 1) - p - 1;
build(T[0], 1, q);
for(int i = 1; i <= n; ++i) {
int xx = lower_bound(p + 1, p + q + 1, a[i]) - p;
init(T[i], T[i - 1], 1, q, xx);
}
for(int i = 1; i <= m; ++i)
{
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", p[ask(T[l - 1], T[r], 1, q, (r - l + 1) / 2)]);
}
return 0;
}