Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define task "GPICTURES"
- #include <iostream>
- #include <cstdio>
- #include <algorithm>
- #include <vector>
- #include <queue>
- #include <map>
- using namespace std;
- using ll = long long;
- using ld = long double;
- constexpr int N = 1e6 + 5;
- #define Find(x, v) (lower_bound(x.begin(), x.end(), v) - x.begin() + 1)
- void Read();
- void Compress();
- struct FenwickTree
- {
- vector<int> a;
- int n;
- void Assign(int m)
- {
- this->n = m;
- a.assign(m + 2, 0);
- }
- void Update(int p, int v)
- {
- for (; p <= n; p += p & -p)
- a[p] += v;
- }
- int Get(int p)
- {
- int ans(0);
- for (; p; p -= p & -p)
- ans += a[p];
- return ans;
- }
- int Get(int l, int r)
- {
- return Get(r) - Get(l - 1);
- }
- };
- struct Count
- {
- FenwickTree g;
- vector<int> s;
- void Build()
- {
- sort(s.begin(), s.end());
- s.resize(unique(s.begin(), s.end()) - s.begin());
- g.Assign(s.size());
- }
- inline void Update(int v, int c)
- {
- g.Update(Find(s, v), c);
- }
- inline void Insert(int v)
- {
- Update(v, 1);
- }
- inline void Delete(int v)
- {
- Update(v, -1);
- }
- int Get(int l, int r)
- {
- return g.Get(Find(s, l), Find(s, r + 1) - 1);
- }
- } f[N];
- struct SegmentTree
- {
- vector<pair<int, int>> st;
- int n;
- pair<int, int> Merge(const pair<int, int> &a, const pair<int, int> &b)
- {
- if (a.second == b.second)
- return make_pair(a.first + b.first, a.second);
- else if (a.first > b.first)
- return make_pair(a.first - b.first, a.second);
- else if (a.first < b.first)
- return make_pair(b.first - a.first, b.second);
- return make_pair(0, 0);
- }
- void Build(int id, int l, int r, pair<int, int> a[N])
- {
- if (l == r)
- {
- st[id] = a[l];
- return;
- }
- Build(id << 1, l, (l + r) / 2, a);
- Build(id << 1 | 1, (l + r) / 2 + 1, r, a);
- st[id] = Merge(st[id << 1], st[id << 1 | 1]);
- }
- void Build(int n, pair<int, int> a[N])
- {
- this->n = n;
- st.assign(n * 4 + 5, {0, 0});
- Build(1, 1, n, a);
- }
- pair<int, int> Get(int id, int l, int r, const int &a, const int &b)
- {
- if (l > b || r < a)
- return {0, 0};
- if (l >= a && r <= b)
- return st[id];
- return Merge(Get(id << 1, l, (l + r) / 2, a, b), Get(id << 1 | 1, (l + r) / 2 + 1, r, a, b));
- }
- pair<int, int> Get(int l, int r)
- {
- return Get(1, 1, n, l, r);
- }
- } row[N], sweep;
- int m, n, h, w;
- vector<int> a[N], compress;
- pair<int, int> represent[N];
- void Solve()
- {
- for (int i = 1; i <= m; ++i)
- {
- for (int j = 1; j <= n; ++j)
- {
- f[a[i][j]].s.emplace_back(i);
- represent[j] = make_pair(1, a[i][j]);
- }
- row[i].Build(n, represent);
- }
- for (int i = 1; i <= m * n; ++i)
- f[i].Build();
- ll ans(0);
- for (int i = 1; i <= n; ++i)
- {
- for (int j = 1; j <= m; ++j)
- {
- if (i > w)
- f[a[j][i - w]].Delete(j);
- f[a[j][i]].Insert(j);
- }
- if (i >= w)
- {
- for (int j = 1; j <= m; ++j)
- represent[j] = row[j].Get(i - w + 1, i);
- sweep.Build(m, represent);
- for (int j = h; j <= m; ++j)
- {
- pair<int, int> candidate = sweep.Get(j - h + 1, j);
- // cerr << j << " " << i << ": " << candidate.second << " - " << candidate.first << "\n";
- if (candidate.first == 0)
- ++ans;
- else
- {
- int v = f[candidate.second].Get(j - h + 1, j);
- if (v * 2 <= h * w)
- ++ans;
- }
- }
- }
- }
- cout << ans;
- }
- int32_t main()
- {
- ios_base::sync_with_stdio(0);
- cin.tie(0);
- cout.tie(0);
- if (fopen(task ".INP", "r"))
- {
- freopen(task ".INP", "r", stdin);
- freopen(task ".OUT", "w", stdout);
- }
- Read();
- Compress();
- Solve();
- }
- void Read()
- {
- cin >> m >> n >> h >> w;
- for (int i = 1; i <= m; ++i)
- {
- a[i].assign(n + 1, 0);
- for (int j = 1; j <= n; ++j)
- {
- cin >> a[i][j];
- compress.emplace_back(a[i][j]);
- }
- }
- }
- void Compress()
- {
- sort(compress.begin(), compress.end());
- compress.resize(unique(compress.begin(), compress.end()) - compress.begin());
- for (int i = 1; i <= m; ++i)
- for (int j = 1; j <= n; ++j)
- a[i][j] = Find(compress, a[i][j]);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement