2019 Multi-University Training Contest 2 hdu6602 Longest Subarray

2019 Multi-University Training Contest 2 hdu6602 Longest Subarray

给定一个值域在 \([1,\ m]\) 的长度为 \(n\) 的正整数序列 \(a_i\) ,求出最长的子序列满足:\[\forall x\in[1,\ m],\ \displaystyle\sum_{i=l}^r[a_i=x]=0,\ or \displaystyle\sum_{i=l}^r[a_i=x]\ge k\]

\(n,\ m,\ k\leq10^5\)

数据结构


考虑对于每个右端点 \(i\) ,不合法的区间为 \([i\) 的上 \(k-1\) 次出现的位置 \(+1\) \(,\ i]\) 。考虑对于这一段区间打 \(+1\) 标记,询问合法的区间即为找到最小的为 \(0\) 的位置,可以用线段树维护。由于只需要考虑不同的数的贡献,因此每次修改需要将上一次修改撤销。

时间复杂度 \(O(n\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int n, m, k, a[maxn], pos[maxn], pre[maxn], lst[maxn];

vector <int> vec[maxn];

#define mid ((l + r) >> 1)
#define lson k << 1, l, mid
#define rson k << 1 | 1, mid + 1, r

int tag[maxn << 2], val[maxn << 2];

inline void pushtag(int k, int x) {
  tag[k] += x, val[k] += x;
}

inline void pushdown(int k) {
  int &x = tag[k];
  if (x) {
    pushtag(k << 1, x);
    pushtag(k << 1 | 1, x);
    x = 0;
  }
}

inline void maintain(int k) {
  val[k] = min(val[k << 1], val[k << 1 | 1]);
}

void upd(int k, int l, int r, int ql, int qr, int x) {
  if (ql <= l && r <= qr) {
    pushtag(k, x); return;
  }
  pushdown(k);
  if (ql <= mid) upd(lson, ql, qr, x);
  if (qr > mid) upd(rson, ql, qr, x);
  maintain(k);
}

int query(int k, int l, int r) {
  if (l == r) return l;
  pushdown(k);
  assert(val[k] >= 0);
  if (val[k]) return n + 1;
  return val[k << 1] ? query(rson) : query(lson);
}

#undef mid
#undef lson
#undef rson

inline void add(int x, int v) {
  if (x) upd(1, 1, n, lst[x] + 1, x, v);
}

void solve() {
  memset(pos, 0, (n + 1) << 2);
  memset(lst, 0, (n + 1) << 2);
  memset(tag, 0, (n + 1) << 4);
  memset(val, 0, (n + 1) << 4);
  for (int i = 1; i <= m; i++) {
    vec[i].clear();
  }
  for (int i = 1; i <= n; i++) {
    scanf("%d", a + i);
    vec[a[i]].push_back(i);
    pre[i] = pos[a[i]], pos[a[i]] = i;
  }
  for (int i = 1; i <= m; i++) {
    int sz = vec[i].size();
    for (int j = k - 1; j < sz; j++) {
      lst[vec[i][j]] = vec[i][j - k + 1];
    }
  }
  int ans = 0;
  for (int i = 1; i <= n; i++) {
    add(pre[i], -1), add(i, 1);
    ans = max(ans, i - query(1, 1, n) + 1);
  }
  printf("%d\n", ans);
}

int main() {
  while (~scanf("%d %d %d", &n, &m, &k)) {
    solve();
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Juanzhang/p/11312261.html