1. 程式人生 > >[洛谷P3765]總統選舉

[洛谷P3765]總統選舉

題目大意:有$n(n\leqslant5\times10^5)$個數,有$m(m\leqslant5\times10^5)$次詢問。

一次詢問形如$l\;r\;s\;k\;w_1\;w_2\dots w_k:$每次詢問$[l_i,r_i]$內的出現次數大於一半的數,如果沒有,則為$s$。這次詢問後結束後$k(\sum k\leqslant10^6)$個位置的數$w_i$變成詢問答案。

題解:求大於一半的數可以用[洛谷P2397]yyy loves Maths VI (mode)來做,帶修改,可以用線段樹,維護區間最大的數,以及這個數比一半多了多少。但是求出來的答案只是可能的解(因為沒有出現次數保證大於一半),可以用平衡樹求出這個數在這個區間中出現次數,判斷是否合法。修改暴力改

卡點:初值計數器賦成$-1$,導致轉移出鍋

 

C++ Code:

#include <cstdio>
#include <cctype>
//#define ONLINE_JUDGE
namespace R {
	int x;
	#ifdef ONLINE_JUDGE
	#define M 1 << 27
	char op[M], *ch;
	inline void init() {fread(ch = op, 1, M, stdin);}
	inline int read() {
		while (isspace(*ch)) ch++;
		for (x = *ch & 15, ch++; isdigit(*ch); ch++) x = x * 10 + (*ch & 15);
		return x;
	}
	#else
	char ch;
	inline int read() {
		ch = getchar();
		while (isspace(ch)) ch = getchar();
		for (x = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) x = x * 10 + (ch & 15);
		return x;
	}
	#endif
}
using R::read;

#define maxn 500010

int n, m;
int s[maxn];

namespace SgT {
	struct node {
		int s, cnt; //s為區間可能眾數,cnt這個數比一半區間長度多多少
		inline node(int __s = 0, int __cnt = 0) {s = __s, cnt = __cnt;}
		inline friend node operator + (const node &lhs, const node &rhs) {
			if (lhs.s == rhs.s) return node(lhs.s, lhs.cnt + rhs.cnt);
			if (lhs.cnt > rhs.cnt) return node(lhs.s, lhs.cnt - rhs.cnt);
			else return node(rhs.s, rhs.cnt - lhs.cnt);
		}
	} V[maxn << 2];
	inline void update(int rt) {
		V[rt] = V[rt << 1] + V[rt << 1 | 1];
	}

	void build(int rt, int l, int r) {
		if (l == r) {
			V[rt] = node(s[l], 1);
			return ;
		}
		int mid = l + r >> 1;
		build(rt << 1, l, mid);
		build(rt << 1 | 1, mid + 1, r);
		update(rt);
	}
	
	int pos, num;
	void __modify(int rt, int l, int r) {
		if (l == r) {
			V[rt] = node(num, 1);
			return ;
		}
		int mid = l + r >> 1;
		if (pos <= mid) __modify(rt << 1, l, mid);
		else __modify(rt << 1 | 1, mid + 1, r);
		update(rt);
	}
	void modify(int __pos, int __num) {
		pos = __pos, num = __num;
		__modify(1, 1, n);
	}
	
	int L, R;
	node __query(int rt, int l, int r) {
		if (L <= l && R >= r) return V[rt];
		int mid = l + r >> 1;
		node ans;
		if (L <= mid) ans = __query(rt << 1, l, mid);
		if (R > mid) ans = ans + __query(rt << 1 | 1, mid + 1, r);
		return ans;
	}
	int query(int __L, int __R, int tg = 0) {
		L = __L, R = __R;
		return __query(1, 1, n).s;
	}
}

namespace Treap {
	int root[maxn];
	#define N 1000010 + maxn
	int seed = 20040826;
	inline int rand() {return seed *= 48271;}
	int ta, tb, tmp, res;

	int lc[N], rc[N], pri[N], V[N], sz[N], idx;
	inline int nw(int x) {
		pri[++idx] = rand();
		sz[idx] = 1;
		V[idx] = x;
		return idx;
	}
	inline int update(int rt) {
		sz[rt] = sz[lc[rt]] + sz[rc[rt]] + 1;
		return rt;
	}

	void split(int rt, int k, int &x, int &y) {
		if (!rt) x = y = 0;
		else {
			if (V[rt] <= k) split(rc[rt], k, rc[rt], y), x = update(rt);
			else split(lc[rt], k, x, lc[rt]), y = update(rt);
		}
	}
	int merge(int x, int y) {
		if (!x || !y) return x | y;
		if (pri[x] > pri[y]) {rc[x] = merge(rc[x], y); return update(x);}
		else {lc[y] = merge(x, lc[y]); return update(y);}
	}
	
	void insert(int &rt, int x) {
		if (!rt) rt = nw(x);
		else {
			split(rt, x, ta, tb);
			rt = merge(merge(ta, nw(x)), tb);
		}
	}
	void erase(int &rt, int x) {
		split(rt, x, ta, tb);
		split(ta, x - 1, ta, tmp);
		rt = merge(ta, tb);
	}
	
	int gtrnk(int &rt, int x) {
		split(rt, x, ta, tb);
		res = sz[ta];
		merge(ta, tb);
		return res;
	}
	
	int query(int &rt, int l, int r) {
//		printf("%d %d\n", gtrnk(rt, r), gtrnk(rt, l));
		return gtrnk(rt, r) - gtrnk(rt, l - 1);
	}
	void modify(int tg, int &before, int after) {
		erase(root[before], tg);
		insert(root[after], tg);
		before = after;
	}
	#undef N
}
using Treap::root;

int main() {
	#ifdef ONLINE_JUDGE
	R::init();
	#endif
	n = read(), m = read();
	for (int i = 1; i <= n; i++) Treap::insert(root[s[i] = read()], i);
	SgT::build(1, 1, n);
	while (m --> 0) {
		int l = read(), r = read(), s = read(), k = read();
		int tmp = SgT::query(l, r);
		int CNT = Treap::query(root[tmp], l, r);
		if (CNT <= (r - l + 1 >> 1)) tmp = s;
		printf("%d\n", tmp);
		for (int i = 0, x; i < k; i++) {
			x = read();
			SgT::modify(x, tmp);
			Treap::modify(x, ::s[x], tmp);
		}
	}
	int tmp = SgT::query(1, n);
	int CNT = Treap::query(root[tmp], 1, n);
	if (CNT <= n >> 1) tmp = -1;
	printf("%d\n", tmp);
	return 0;
}