[BZOJ3207][花神的嘲讽计划Ⅰ][主席树+Hash]

    xiaoxiao2021-03-25  103

    [BZOJ3207][花神的嘲讽计划Ⅰ][主席树+Hash]

    题目大意:

    给定一个 N<=100000 个数的序列和 M<=100000 个询问和 k ,每个询问包含k 2个数字: l,r,b[1],b[2]...b[k] ,要求输出 b[1] b[k] [l,r] 中是否出现。

    思路:

    因为 b[1],b[2]...b[k] 是一段连续的数字,所以可以把它 Hash 成一个数然后用这个数来判断是否出现,这个数可以对 [1,INF] ( INF 实际值是unsigned long long的最大值)这个区间在 [1,N] 都开一棵可持久化线段树记录之前的版本。然后查询 Hash 值有没有出现就好了

    代码:

    #include <bits/stdc++.h> using namespace std; namespace IO { inline char get(void) { static char buf[1000000], *p1 = buf, *p2 = buf; if (p1 == p2) { p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin); if (p1 == p2) return EOF; } return *p1++; } inline void read(int &x) { x = 0; static char c; bool f = 0; for (; !(c >= '0' && c <= '9'); c = get()) if (c == '-') f = 1; for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get()); if (f) x = -x; } inline void write(int x) { if (!x) return (void)puts("0"); if (x < 0) putchar('-'), x = -x; static short s[12], t; while (x) s[++t] = x % 10, x /= 10; while (t) putchar('0' + s[t--]); putchar('\n'); } }; const int Maxn = 100005; typedef unsigned long long ll; int ls[Maxn * 80], rs[Maxn * 80], sum[Maxn * 80], rt[Maxn], sz; inline void insert(int x, int &y, ll l, ll r, ll pos) { y = ++sz; sum[y] = sum[x] + 1; ls[y] = ls[x], rs[y] = rs[x]; if (l == r) return ; ll mid = (l >> 1) + (r >> 1) + (l & r & 1); if (pos <= mid) insert(ls[x], ls[y], l, mid, pos); else insert(rs[x], rs[y], mid + 1, r, pos); } inline int query(int x, int y, ll l, ll r, ll pos) { if (sum[y] - sum[x] == 0) return 0; if (l == r) return 1; ll mid = (l >> 1) + (r >> 1) + (l & r & 1); if (pos <= mid) return query(ls[x], ls[y], l, mid, pos); else return query(rs[x], rs[y], mid + 1, r, pos); } int n, m, k, a[Maxn]; ll hash[Maxn], w; int main(void) { //freopen("in.txt", "r", stdin); IO::read(n), IO::read(m), IO::read(k); for (int i = 1; i <= n; i++) IO::read(a[i]); for (int i = 1; i <= n; i++) hash[i] = hash[i - 1] * 99997 + a[i]; w = 1; for (int i = 1; i <= k; i++) w *= 99997; for (int i = k; i <= n; i++) insert(rt[i - 1], rt[i], 1, ULLONG_MAX, hash[i] - hash[i - k] * w); for (int i = 1, x, y, s; i <= m; i++) { IO::read(x), IO::read(y); ll h = 0; for (int j = 1; j <= k; j++) IO::read(s), h = h * 99997 + s; if (y - x + 1 >= k && query(rt[x + k - 2], rt[y], 1, ULLONG_MAX, h)) puts("No"); else puts("Yes"); } return 0; }

    完。

    By g1n0st

    转载请注明原文地址: https://ju.6miu.com/read-24950.html

    最新回复(0)