题目大意:
解题思路:
1.摩尔投票法:
-
题意是找n个数内出现次数大于n/2的数 保证存在这个数用的方法叫做摩尔投票法
-
首先我们注意到这样一个现象: 在任何数组中,出现次数大于该数组长度一半的值只能有一个。
-
摩尔投票法的基本思想很简单,在每一轮投票过程中,从数组中找出一对不同的元素,将其从数组中删除。
-
这样不断的删除直到无法再进行投票,如果数组为空,则没有任何元素出现的次数超过该数组长度的一半。如果只存在一种元素,那么这个元素则可能为目标元素。
有了这个前置技能以后 这道题的第一个思路应该很明显了:用线段树维护一个区间的cnt和众数
但是用线段树维护 必须保证维护的东西满足区间可加性
显然摩尔投票法是有区间可加性的
具体来说 如果两个儿子的众数相同 这个节点的众数就等于儿子的众数 cnt就等于两个儿子的cnt相加
如果不同 这个节点的众数就等于cnt较大的那个儿子的众数 cnt就等于大的减去小的
写成代码也很简单
void pushup(int rt) {
if(tr[rt<<1] == tr[rt<<1|1]) {
tr[rt] = tr[rt<<1];
cnt[rt] = cnt[rt<<1] + cnt[rt<<1|1];
} else if(cnt[rt<<1] >= cnt[rt<<1|1]) {
tr[rt] = tr[rt<<1];
cnt[rt] = cnt[rt<<1] - cnt[rt<<1|1];
} else {
tr[rt] = tr[rt<<1|1];
cnt[rt] = cnt[rt<<1|1] - cnt[rt<<1];
}
}
2.splay验证
题目是不保证一定存在这个数。那就是意味着我们找到的这个数不一定是对的
那么我们要去 c h e c k check check这个数,怎么 c h e c k check check呢?
我们对于每个人建立一个splay,里面插入支持人的编号,我们说这个人在询问的 [ l , r ] [l,r] [l,r]里面是众数,因为就是每个数字不一样,那么我们只要对这个 s p l a y splay splay里面查询 r a n k rank rank,就是你查询比 r r r小有多少人,比 l l l小有多少人,做差就好了
AC code
这里splay很离谱,查询rank里面有大量的不存在的数,我们对于查不到的数,我们要把这个数的前驱splay到根节点,才能保证复杂度
封装起来每个splay 都有一个root,旋根的时候要记得跟新root
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x7fffffff
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define ls(x) T[x].ch[0]
#define rs(x) T[x].ch[1]
#define fa(x) T[x].fa
#define endl '\n'
using namespace std;
const int N = 5e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
int arr[maxn];
struct node {
int fa;//父亲
int ch[2];// 存储左右儿子的位置
int val;
int rec;
int sum;
}T[N];
int tot = 0;
struct Splay {
int root;
void update(int x) {T[x].sum = T[ls(x)].sum + T[rs(x)].sum + T[x].rec;}
int ident(int x) {return T[fa(x)].ch[0] == x ? 0 : 1;}
void connect(int x, int fa, int how) {// 把x变成fa的how儿子
T[fa].ch[how] = x;
T[x].fa = fa;
}
void rotate(int x) { // 把x转到fa位置
int Y = fa(x), R = fa(Y);
int YSON = ident(x), RSON = ident(Y);
connect(T[x].ch[YSON^1],Y,YSON);
connect(Y,x,YSON^1);
connect(x,R,RSON);
update(Y);
update(x);
}
void splay(int x, int to) { // 把x转到to的位置
to = fa(to);
while(fa(x) != to) {
int y = fa(x);
if(T[y].fa == to) rotate(x);
else if(ident(x) == ident(y)) rotate(y), rotate(x);
else rotate(x), rotate(x);
}
}
int newnode(ll v, int f) {//开新节点
T[++ tot].fa = f;
T[tot].rec = T[tot].sum = 1;
T[tot].val = v;
return tot;
}
void Insert(ll x) {//插入新的节点
int now = root;
if(root == 0) {newnode(x,0);root=tot;}
else {
while(1) {
T[now].sum ++;
if(T[now].val == x) {T[now].rec++;splay(now,root);return;}
int nxt = x < T[now].val ? 0 : 1;
if(!T[now].ch[nxt]) {
int p = newnode(x,now);
T[now].ch[nxt] = p;
splay(p,root);
root = p;
return;
}
now = T[now].ch[nxt];
}
}
}
int find(int x) {//查找x在哪里?
int now = root;
while(1) {
if(!now) return now;
if(T[now].val == x) {splay(now,root); root = now; return now;}
int nxt = x < T[now].val ? 0 : 1;
now = T[now].ch[nxt];
}
}
int rak(int x) {
int now = root, ans = 0;
int las;
while(now) {
las = now;
if(T[now].val == x) {
ans = ans + T[T[now].ch[0]].sum + 1;
splay(now,root);
root = now;
return ans;
}
int nxt = x < T[now].val ? 0 : 1;
if(nxt == 1) ans = ans + T[T[now].ch[0]].sum + T[now].rec;
now = T[now].ch[nxt];
}
splay(las,root), root = las;// 没有这句话会T飞了
return ans;
}
void delet(int x) {
int pos=find(x);
if(!pos) return;
if(T[pos].rec>1) {T[pos].rec--,T[pos].sum--;return ;}
else {
if(!T[pos].ch[0]&&!T[pos].ch[1]) {root=0;return ;}
else if(!T[pos].ch[0]) {root=T[pos].ch[1];T[root].fa=0;return ;}
else
{
int left=T[pos].ch[0];
while(T[left].ch[1]) left=T[left].ch[1];
splay(left,T[pos].ch[0]);
connect(T[pos].ch[1],left,1);
connect(left,0,1);
root = left;
update(left);
}
}
}
}splay[N];
struct Segtree {
int tr[N];
int cnt[N];
void pushup(int rt) {
if(tr[rt<<1] == tr[rt<<1|1]) {
tr[rt] = tr[rt<<1];
cnt[rt] = cnt[rt<<1]+cnt[rt<<1|1];
} else if(cnt[rt<<1] >= cnt[rt<<1|1]) {
tr[rt] = tr[rt<<1];
cnt[rt] = cnt[rt<<1] - cnt[rt<<1|1];
} else {
tr[rt] = tr[rt<<1|1];
cnt[rt] = cnt[rt<<1|1] - cnt[rt<<1];
}
}
void build(int rt, int l, int r) {
if(l == r) {
tr[rt] = arr[l];
cnt[rt] = 1;
return;
}
build(Lson);
build(Rson);
pushup(rt);
}
void update(int rt, int l, int r, int pos, int val) {
if(l == r) {
tr[rt] = val;
cnt[rt] = 1;
return;
}
if(pos <= mid) update(Lson,pos,val);
else update(Rson,pos,val);
pushup(rt);
}
PII ask(int rt, int l, int r, int posl, int posr) {
if(posl <= l && posr >= r) return {tr[rt],cnt[rt]};
PII res = {-INF,-INF};
if(posl <= mid) res = ask(Lson,posl,posr);
if(posr > mid) {
PII ans = ask(Rson,posl,posr);
if(res.first == -INF) return ans;
if(ans.first == res.first) ans.second += res.second;
else if(ans.second > res.second) ans.second -= res.second;
else ans.first = res.first, ans.second = res.second - ans.second;
return ans;
}
return res;
}
}sgt;
int main() {
IOS;
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; ++ i) splay[i].Insert(INF), splay[i].Insert(-INF);
for(int i = 1; i <= n; ++ i) cin >> arr[i], splay[arr[i]].Insert(i);
sgt.build(1,1,n);
while(m--) {
int l, r, s, k;
cin >> l >> r >> s >> k;
int pe = sgt.ask(1,1,n,l,r).first;
int sum = splay[pe].rak(r) - splay[pe].rak(l-1);
if(sum > (r-l+1)/2) cout << pe << endl, s = pe;
else cout << s << endl;
while(k --) {
int x;
cin >> x;
splay[arr[x]].delet(x);
splay[s].Insert(x);
sgt.update(1,1,n,x,s);
arr[x] = s;
}
}
int last = sgt.ask(1,1,n,1,n).first;
int sum = splay[last].rak(n)-1;
if(sum>n/2) cout << last;
else cout << "-1";
return 0;
}
/*
2 2
1 1
2 2 2 1 2
1 2 1 1 1
*/