【分塊】【P2801】教主的魔法
阿新 • • 發佈:2018-12-10
Description
給你一個長度為 \(n\) 的序列,要求資瓷區間加,查詢區間大於等於 \(k\) 的數的個數
Input
第一行是 \(n~,~Q\) 代表序列長度和操作個數
下面一行代表序列
下面 \(Q\) 行,每行四個引數,分別為 \(opt~,~l,~r~,w\)
如果 \(opt~=~M\) 則區間加
如果 \(opt~=~A\) 則查詢
Output
對每次查詢輸出結果
Hint
\(1~\leq~n~\leq~1000000~,~1~\leq~q~\leq~1000\)
Solution
看到序列這麼長,運算元這麼少,常見的複雜度平衡的資料結構大概不起作用,於是考慮分塊。
分塊後考慮塊內如何查詢答案:可以對塊內整個進行排序,然後lowerbound一下即可。
考慮修改時,如果修改整個塊則不會對塊內大小順序造成影響,可以直接處理。
邊界上直接暴力修改,修改完暴力排序,因為只會暴力兩個塊,所以複雜度還是 \(O(\sqrt{n}~(\log {\sqrt{n}})\) 的,總複雜度 \(O(q~\sqrt{n}~\log \sqrt{n})\),可以通過本題。
Code
#include <cmath> #include <cstdio> #include <algorithm> #ifdef ONLINE_JUDGE #define freopen(a, b, c) #endif #define rg register #define ci const int #define cl const long long typedef long long int ll; namespace IPT { const int L = 1000000; char buf[L], *front=buf, *end=buf; char GetChar() { if (front == end) { end = buf + fread(front = buf, 1, L, stdin); if (front == end) return -1; } return *(front++); } } template <typename T> inline void qr(T &x) { rg char ch = IPT::GetChar(), lst = ' '; while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar(); while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar(); if (lst == '-') x = -x; } template <typename T> inline void ReadDb(T &x) { rg char ch = IPT::GetChar(), lst = ' '; while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar(); while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar(); if (ch == '.') { ch = IPT::GetChar(); double base = 1; while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar(); } if (lst == '-') x = -x; } namespace OPT { char buf[120]; } template <typename T> inline void qw(T x, const char aft, const bool pt) { if (x < 0) {x = -x, putchar('-');} rg int top=0; do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10); while (top) putchar(OPT::buf[top--]); if (pt) putchar(aft); } const int maxn = 1000010; int n, q; ll MU[maxn], belong[maxn], temp[maxn], tag[maxn], lc[maxn], rc[maxn]; void rebuild(ci); int main() { freopen("1.in", "r", stdin); qr(n); qr(q); for (rg int i = 1; i <= n; ++i) qr(MU[i]); for (rg int i = 1; i <= n; ++i) temp[i] = MU[i]; for (rg int i = 1, sn = sqrt(n); i <= n; ++i) belong[i] = i / sn; for (rg int i = 1, j = 1; i <= n; i = j) { while(belong[j] == belong[i]) ++j; std::sort(temp + i, temp + j); lc[belong[i]] = i; rc[belong[i]] = j; } int a, b, c; rg char ch; while (q--) { do {ch = IPT::GetChar();} while((ch != 'M') && (ch != 'A')); if (ch == 'M') { a = b = c = 0; qr(a); qr(b); qr(c); if (belong[a] == belong[b]) { for (rg int i = a; i <= b; ++i) { MU[i] += c; } rebuild(a); } else { for (rg int i = belong[a] + 1; i < belong[b]; ++i) tag[i] += c; for (rg int i = a; belong[i] == belong[a]; ++i) MU[i] += c; for (rg int i = b; belong[i] == belong[b]; --i) MU[i] += c; rebuild(a); rebuild(b); } } else { a = b = c = 0; qr(a); qr(b); qr(c); int _ret = 0; if (belong[a] == belong[b]) { c -= tag[belong[a]]; for (rg int i = a; i <= b; ++i) if (MU[i] >= c) ++_ret; } else { for (rg int i = belong[a] + 1; i < belong[b]; ++i) _ret += temp + rc[i] - std::lower_bound(temp + lc[i], temp + rc[i], c - tag[i]); c -= tag[belong[a]]; for (rg int i = a; belong[i] == belong[a]; ++i) _ret += MU[i] >= c; c += tag[belong[a]]; c -= tag[belong[b]]; for (rg int i = b; belong[i] == belong[b]; --i) _ret += MU[i] >= c; } qw(_ret, '\n', true); } } return 0; } void rebuild(ci a) { for (rg int i = lc[belong[a]]; belong[i] == belong[a]; ++i) temp[i] = MU[i]; std::sort(temp + lc[belong[a]], temp + rc[belong[a]]); }
Summary
當查詢較少但是序列較長時,考慮分塊來降低維護代價。