绝对众数

出现次数大于长度一半的数,一般来讲摩尔投票即可,但是还有神秘做法。

考虑统计每个二进制位上 0/1 的出现次数,如果绝对众数存在,那么它的那一位上一定是出现较多的那个。我们可以 \(O(n\log n)\) 找出可能的答案。注意到出现次数具有可减性,在一些情况下比摩尔投票维护起来更简单。

比如我们换到二维,每次统计一个子矩形里的绝对众数,这个方法就直接对每一位开个前缀和即可。

#include <bits/stdc++.h>

using namespace std;

const int N = 1025, M = 1e6 + 5;

namespace IO{
	inline char gc(){
		static const int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>T get_integer(){
		char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
		while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
	}
	inline int read(){return get_integer<int>();}
}using namespace IO;
inline void write(int x){
	if(x==-1){
		putchar('-'),putchar('1'),putchar('\n');
		return;
	}
	static int st[20],top=0;
	while(x) st[++top]=x%10,x/=10;
	while(top) putchar(st[top--]+48);
	putchar('\n');
}

int a[N][N], sum[N][N], n, m, q;
int cnt[M], lx[M], rx[M], ly[M], ry[M], p[M], res[M];
bool vis[M];
vector<pair<int, int> > pos[M];
vector<pair<pair<int, int>, int>> ask[M];

#define mp make_pair

inline int calc(int z, int lx, int ly, int rx, int ry) {
	int res = 0;
	for (int i = lx; i <= rx; ++i) {
		vector<pair<int, int> > :: iterator itl, itr;
		itl = lower_bound(pos[z].begin(), pos[z].end(), make_pair(i, 0));
		itr = upper_bound(pos[z].begin(), pos[z].end(), make_pair(i, 100000000));
		int ll = lower_bound(itl, itr, make_pair(i, ly)) - itl;
		int rr = upper_bound(itl, itr, make_pair(i, ry)) - itl;
		--rr; if (ll <= rr) res += rr - ll + 1;
	} return res;
}

set<int> st;

int tree[N];

inline void add(int x) {
	for (int i = x; i <= m; i += i & -i) ++tree[i]; 
}

inline void del(int x) {
	for (int i = x; i <= m; i += i & -i) tree[i] = 0;
}

inline int query(int x) {
	int res = 0;
	for (int i = x; i; i -= i & -i) res += tree[i];
	return res;
}

inline void calc(int x) {
	if (ask[x].empty()) return ;
	sort(ask[x].begin(), ask[x].end());
	sort(pos[x].begin(), pos[x].end());
	for (int i = 0, j = 0; i < ask[x].size(); ++i) {
		while (j < pos[x].size() && pos[x][j].first <= ask[x][i].first.first) {
			add(pos[x][j].second); ++j;
		} int t = ask[x][i].second;
		if (t < 0) res[-t] -= query(ask[x][i].first.second);
		else res[t] += query(ask[x][i].first.second);
	}
	for (pair<int, int> i : pos[x]) del(i.second);
}

int main() {
	n = read(); m = read(); q = read();
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j) {
			a[i][j] = read(), ++cnt[a[i][j]];
			pos[a[i][j]].push_back(make_pair(i, j));
		}
	for (int i = 1; i <= q; ++i) {
		lx[i] = read(); ly[i] = read(); rx[i] = read(); ry[i] = read();
	}
	for (int k = 0; k < 20; ++k) {
		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= m; ++j) {
				sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + ((a[i][j] >> k) & 1);
			}
		}
		for (int i = 1; i <= q; ++i) {
			int sm = (rx[i] - lx[i] + 1) * (ry[i] - ly[i] + 1);
			int c1 = sum[rx[i]][ry[i]] - sum[rx[i]][ly[i] - 1] - sum[lx[i] - 1][ry[i]] + sum[lx[i] - 1][ly[i] - 1];
			int c0 = sm - c1;
			p[i] |= (c1 >= c0) << k;
		}
	}
	for (int i = 1; i <= q; ++i) {
		st.insert(p[i]);
		ask[p[i]].push_back(mp(mp(rx[i], ry[i]), i));
		ask[p[i]].push_back(mp(mp(lx[i] - 1, ry[i]), -i));
		ask[p[i]].push_back(mp(mp(rx[i], ly[i] - 1), -i));
		ask[p[i]].push_back(mp(mp(lx[i] - 1, ly[i] - 1), i));
	}
	for (int i : st) calc(i);
	for (int i = 1; i <= q; ++i) {
		int sm = (rx[i] - lx[i] + 1) * (ry[i] - ly[i] + 1);
		if (res[i] * 2 <= sm) puts("-1");
		else printf("%d\n", p[i]);
	}
	return 0;
}
posted @ 2023-10-26 21:26  Smallbasic  阅读(89)  评论(0)    收藏  举报