Luogu 3765
题意:维护序列的区间大于一半数的众数,带修。
第一眼以为带修主席树,感觉肯定跑不过
前置知识:Luogu 2397
求序列大于一半数的众数
本题可以采用摩尔投票法求,即将不同数两两消除,最后一定剩下的是这个众数。
这个方法必须存在大于一半数的众数
然后看这题,显然摩尔投票法是满足可加性的,那么线段树维护之。
但是如果不满足存在大于一半数的众数怎么办?
我们可以维护一个数在某个区间出现次数,这个方法是经典套路,静态则用 vector
排序后二分,而动态则需要名次树Splay
维护。具体方法为在名次树上类似静态方法二分即可。
然后每次查询,更改即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<set>
#include<vector>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {
const int MAXN = 500000 + 5, INF = 2000000000;
int n, m, vt[MAXN];
struct qwq {
vector<int > a;
void insert(int x) {a.insert(lower_bound(a.begin(), a.end(), x), x);}
void del(int x) {a.erase(lower_bound(a.begin(), a.end(), x));}
int rank(int x) {return lower_bound(a.begin(), a.end(), x) - a.begin() + 1;}
int kth(int k) {return a[k - 1];}
int pre(int x) {return a[lower_bound(a.begin(), a.end(), x) - a.begin() - 1];}
int succ(int x) {return a[upper_bound(a.begin(), a.end(), x) - a.begin()];}
}s[MAXN];
int chk(int l, int r, int i) { // 1
if (i == 0) return 0;
return upper_bound(s[i].a.begin(), s[i].a.end(), r) - upper_bound(s[i].a.begin(), s[i].a.end(), l - 1);
}
#define lc (o << 1)
#define rc (o << 1 | 1)
#define M ((l + r) >> 1)
#define lson lc, l, M
#define rson rc, M + 1, r
int cnt[MAXN * 4], num[MAXN * 4];
void pushup(int o) { // 1
if (num[lc] == num[rc]) num[o] = num[lc], cnt[o] = cnt[lc] + cnt[rc];
else {
if (cnt[lc] > cnt[rc]) cnt[o] = cnt[lc] - cnt[rc], num[o] = num[lc];
else cnt[o] = cnt[rc] - cnt[lc], num[o] = num[rc];
}
}
void build(int o, int l, int r) { // 1
cnt[o] = num[o] = 0;
if (l == r) return ; else {
build(lson), build(rson);
pushup(o);
}
}
int query(int o, int l, int r, int x, int y, int &whw) {
if (x <= l && r <= y) { // 1
return whw = cnt[o], num[o];
}
int ret = 0, cc = 0;
if (x <= M) {
ret = query(lson, x, y, cc);
}
if (M < y) {
int tmp1, tmp2;
tmp1 = query(rson, x, y, tmp2);
if (tmp1 == ret) cc += tmp2; else {
if (tmp2 > cc) ret = tmp1, cc = tmp2 - cc;
else cc = cc - tmp2;
}
}
return whw = cc, ret;
}
void update(int o, int l, int r, int p, int v) { // 1
if (l == r) {
cnt[o] = 1, num[o] = v;
return ;
}
if (p <= M) update(lson, p, v);
else update(rson, p, v);
pushup(o);
}
void clean() {
}
int solve() {
clean();
cin >> n >> m;
build(1, 1, n);
for (int i = 1; i <= n; ++i)
scanf("%d", &vt[i]),
update(1, 1, n, i, vt[i]), s[vt[i]].insert(i), s[i].insert(INF), s[i].insert(-INF);
while (m--) {
int l, r, si, k; scanf("%d%d%d%d", &l ,&r, &si, &k);
int gg, ret = query(1, 1, n, l, r, gg);
if (chk(l, r, ret) <= (r - l + 1) / 2) printf("%d\n", ret = si); else printf("%d\n", ret);
for (int x, i = 1; i <= k; ++i) {
scanf("%d", &x);
update(1, 1, n, x, ret);
s[vt[x]].del(x), s[vt[x] = ret].insert(x);
}
}
int gg, ret = query(1, 1, n, 1, n, gg);
if (chk(1, n, ret) <= (n - 1 + 1) / 2) printf("-1\n"); else printf("%d\n", ret);
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}
/*
3 1000
1 2 3
2 3 0 0
5 400
1 2 3 4 5
1 2 1 1 3
5 5 1 2 2 4
2 4 0 0
5 400
1 5 1 5 5
2 4 0 0
*/