出现次数大于长度一半的数,一般来讲摩尔投票即可,但是还有神秘做法。
考虑统计每个二进制位上 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;
}
标签:itl,putchar,int,make,绝对,pos,众数,pair
From: https://www.cnblogs.com/wwlwakioi/p/17790462.html