題解:P11262 [COTS 2018] 題日 Zapatak

ccxswl發表於2024-11-11

https://www.luogu.com.cn/article/i7ajvm8e

雜湊好題。


題意

給定一個序列,每次詢問給定兩個長度相等的區間,問這兩個區間是否只有一個數不一樣。

思路

發現我們要求的資訊只與數的出現次數有關,自然想到桶。那麼如果有兩個區間合法,那這兩個區間的桶只有兩個位置不同且桶內的值均相差 \(1\)

維護每個區間的桶不太能直接做,且資訊明顯可差分,直接套一個主席樹。

在樹上二分找不同的位置進行判斷即可。

如果當前區間完全相等那麼不滿足條件,左右都不相等的情況只能出現一次不然不合法,左右只有一個不相等遞迴那邊不相等的即可。

程式碼

我的實現需要注意的細節還是挺多的。

複雜度 \(O(n\log n)\)

#include <bits/stdc++.h>

using namespace std;

using ubt = unsigned long long;

const int maxN = 1e5 + 7;

int n, m, Q;
int sor[maxN];
int a[maxN], T[maxN];

const ubt Base = 13331;
ubt B[maxN];

int top[maxN], tot;
struct dat {
  int l, r;
  int len;
  ubt H;
} t[maxN * 20];
void upd(int p) {
  t[p].H = B[t[t[p].l].len] * t[t[p].r].H + t[t[p].l].H;
}
void build(int l, int r, int &p) {
  p = ++tot;
  t[p].len = r - l + 1;
  if (l == r) return;
  int mid = (l + r) >> 1;
  build(l, mid, t[p].l);
  build(mid + 1, r, t[p].r);
  upd(p);
}
void insert(int &p, int w, int K, int l, int r) {
  p = ++tot;
  t[p] = t[w];
  if (l == r) {
    t[p].H = T[K];
    return;
  }
  int mid = (l + r) >> 1;
  if (K <= mid) insert(t[p].l, t[w].l, K, l, mid);
  else insert(t[p].r, t[w].r, K, mid + 1, r);
  upd(p);
}

ubt get(int l, int r) {
  return t[r].H - t[l].H;
}
bool Flag;
bool check(int x0, int y0, int x1, int y1, int l, int r) {
  auto t0 = get(x0, y0), t1 = get(x1, y1);
  if (t0 == t1) return false;
  if (l == r) {
    auto res = abs((int)t0 - (int)t1) == 1;
    return res;
  }
  auto L = get(t[x0].l, t[y0].l) != get(t[x1].l, t[y1].l);
  auto R = get(t[x0].r, t[y0].r) != get(t[x1].r, t[y1].r);
  int mid = (l + r) >> 1;
  if (L && R) {
    if (Flag) return false;
    Flag = true;
    return check(t[x0].r, t[y0].r, t[x1].r, t[y1].r, mid + 1, r)
      && check(t[x0].l, t[y0].l, t[x1].l, t[y1].l, l, mid);
  }
  return R ? check(t[x0].r, t[y0].r, t[x1].r, t[y1].r, mid + 1, r)
    : check(t[x0].l, t[y0].l, t[x1].l, t[y1].l, l, mid);
}

int main() {
  ios::sync_with_stdio(false), cin.tie(nullptr);

  cin >> n >> Q;
  for (int i = 1; i <= n; i++)
    cin >> a[i];

  for (int i = 1; i <= n; i++)
    sor[i] = a[i];
  sort(sor + 1, sor + n + 1);
  m = unique(sor + 1, sor + n + 1) - sor - 1;
  for (int i = 1; i <= n; i++)
    a[i] = lower_bound(sor + 1, sor + m + 1, a[i]) - sor;

  B[0] = 1;
  for (int i = 1; i <= m; i++) 
    B[i] = B[i - 1] * Base;

  build(1, m, top[0]);
  for (int i = 1; i <= n; i++) {
    T[a[i]]++;
    insert(top[i], top[i - 1], a[i], 1, m);
  }

  while (Q--) {
    int l, r, a, b;
    cin >> l >> r >> a >> b;
    Flag = false;
    bool res = check(top[l - 1], top[r], top[a - 1], top[b], 1, m);
    puts(res ? "DA" : "NE");
  }
}

相關文章