BZOJ4939[YNOI2016] 掉進兔子洞
阿新 • • 發佈:2018-09-21
efi urn geo eset its const bug 兔子 nod 就行了
題目藍鏈
Solution
首先,很顯然這題是要用莫隊來處理的。我們先把輸入的數字另外排一下序,然後記錄一下\(p_i\)表示每一個數字對應在排好序的數列裏面是排第幾個。詢問的時候要把一個詢問拆成\(3\)個詢問,然後再並起來。然後在莫隊的時候記錄\(cnt_i\)表示當前數字\(i\)出現的次數,再開一個\(bitset\),假設當前需要加入\(bitset\)的數字是\(x\),我們就令\(bitset\)中的第\(p_x + cnt_x\)位為\(1\),然後\(++cnt_x\)。這樣就會使得把三個\(bitset\)並起來之後,恰好剩下的就是在三個區間都出現了的數字,也就是需要刪除的數字,我們就只需要看並起來之後還剩多少個\(1\)
還有一個問題,就是我們必須要對每一個詢問(拆之前)都要開一個\(bitset\)來存答案,但這會開不下。所以我們就要平衡一下空間復雜度和時間復雜度,把詢問分為幾塊來處理
所以其實我的程序還可以更快一些,那就是在給所有的塊排好序之後再分塊。但這樣寫起來有點麻煩,所以我就懶得卡了
Code
#include <bits/stdc++.h> using namespace std; #define squ(x) ((LL)(x) * (x)) #define debug(...) fprintf(stderr, __VA_ARGS__) typedef long long LL; typedef pair<int, int> pii; inline int read() { int sum = 0, fg = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) fg = -1; for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30); return fg * sum; } const int maxn = 1e5 + 10; const int maxm = 33333 + 10; bitset<maxn> s[maxm]; int len; struct node { int l, r, id; bool operator < (const node &t) const { if (l / len == t.l / len) return r < t.r; return l < t.l; } }op[maxn]; int n, m, top, a[maxn], t[maxn], sum[maxn], cnt[maxn]; void solve(int q) { top = 0; for (int i = 1; i <= q; i++) { int x1 = read(), y1 = read(), x2 = read(), y2 = read(), x3 = read(), y3 = read(); sum[i] = y1 - x1 + y2 - x2 + y3 - x3 + 3; op[++top] = (node){x1, y1, i}, op[++top] = (node){x2, y2, i}, op[++top] = (node){x3, y3, i}; s[i].set(); } sort(op + 1, op + top + 1); int l = 1, r = 0; static bitset<maxn> now; now.reset(); memset(cnt, 0, sizeof cnt); for (int i = 1; i <= top; i++) { int x = op[i].l, y = op[i].r, id = op[i].id; while (l > x) { --l; now.flip(a[l] + cnt[a[l]]); ++cnt[a[l]]; } while (r < y) { ++r; now.flip(a[r] + cnt[a[r]]); ++cnt[a[r]]; } while (l < x) { --cnt[a[l]]; now.flip(a[l] + cnt[a[l]]); ++l; } while (r > y) { --cnt[a[r]]; now.flip(a[r] + cnt[a[r]]); --r; } s[id] &= now; } for (int i = 1; i <= q; i++) printf("%d\n", sum[i] - s[i].count() * 3); } int main() { #ifdef xunzhen freopen("bitset.in", "r", stdin); freopen("bitset.out", "w", stdout); #endif n = read(), m = read(); len = sqrt(n); for (int i = 1; i <= n; i++) t[i] = a[i] = read(); sort(t + 1, t + n + 1); for (int i = 1; i <= n; i++) a[i] = lower_bound(t + 1, t + n + 1, a[i]) - t; while (m) { int x = min(m, 33334); solve(x), m -= x; } return 0; }
Summary
這算是我第一次接觸\(bitset\)吧,它可以快速的完成大量的位運算操作,之後要多做點\(bitset\)的題找找感覺
BZOJ4939[YNOI2016] 掉進兔子洞