1. 程式人生 > >BZOJ4939[YNOI2016] 掉進兔子洞

BZOJ4939[YNOI2016] 掉進兔子洞

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] 掉進兔子洞