题目大意:一个长度为$n(nleqslant5 imes10^5)$的数组,有两个操作:
- $1;l;r;x:$把区间$[l,r]$加上$x$
- $2;x:$询问$x$第一次出现和最后一次出现之间的距离,若没出现输出$-1$
题解:分块,把每个块排个序(可以把数值为第一关键字,位置为第二关键字),整块的加就块上打$tag$,非整块的就暴力重构,查询就在每个块内求这个数出现位置,直接二分查找就行了。设块大小为$S$,修改复杂度$O(dfrac n S+2S)$,查询复杂度$O(dfrac n Slog_2 S)$,$S$略大于$sqrt n$最好。
卡点:无
C++ Code:
#include <algorithm> #include <cstdio> #include <cctype> namespace IO { struct istream { #define M (1 << 24 | 3) char buf[M], *ch = buf - 1; inline istream() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif fread(buf, 1, M, stdin); } inline istream& operator >> (int &x) { while (isspace(*++ch)); for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15); return *this; } inline istream& operator >> (long long &x) { while (isspace(*++ch)); for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15); return *this; } #undef M } cin; struct ostream { #define M (1 << 24 | 3) char buf[M], *ch = buf - 1; int w; inline ostream& operator << (int x) { if (!x) { *++ch = '0'; return *this; } if (x < 0) *++ch = '-', x = -x; for (w = 1; w <= x; w *= 10); for (w /= 10; w; w /= 10) *++ch = (x / w) ^ 48, x %= w; return *this; } inline ostream& operator << (const char x) {*++ch = x; return *this;} inline ~ostream() { #ifndef ONLINE_JUDGE freopen("output.txt", "w", stdout); #endif fwrite(buf, 1, ch - buf + 1, stdout); } #undef M } cout; } #define maxn 500010 const int BSZ = 1 << 10, BNUM = maxn / BSZ + 10; int bel[maxn]; int L[BNUM], R[BNUM]; long long tg[BNUM]; struct node { long long s; int id; inline node() {} inline node(long long __s, int __id) : s(__s), id(__id) {} inline node(int __s, int __id) {s = __s, id = __id;} inline friend bool operator < (const node &lhs, const node &rhs) { return lhs.s == rhs.s ? lhs.id < rhs.id : lhs.s < rhs.s; } } s[maxn]; int n, m, Bnum; int query(const int x) { int max = 0, min = 0; for (int i = 1; i <= Bnum; i++) if (tg[i] <= x) { const int y = x - tg[i]; int l = std::lower_bound(s + L[i], s + R[i], node(y, 0)) - s; if (l != R[i] && s[l].s == y) { int r = std::lower_bound(s + L[i], s + R[i], node(y + 1, 0)) - s - 1; if (!min) min = s[l].id; max = s[r].id; } } if (!min) return -1; return max - min; } int main() { IO::cin >> n >> m; for (int i = 1; i <= n; i++) { IO::cin >> s[i].s; s[i].id = i; bel[i] = (i - 1 >> 10) + 1; } Bnum = bel[n]; for (int i = 1; i <= Bnum; i++) { L[i] = i - 1 << 10, R[i] = L[i] + BSZ; } L[1] = 1, R[Bnum] = n + 1; for (int i = 1; i <= Bnum; i++) { std::sort(s + L[i], s + R[i]); } while (m --> 0) { int op, l, r, x; IO::cin >> op >> l; if (op == 1) { IO::cin >> r >> x; const int lb = bel[l], rb = bel[r]; if (lb == rb) { for (register node *now = s + L[lb]; now != s + R[lb]; ++now) if (l <= now -> id && now -> id <= r) now -> s += x; std::sort(s + L[lb], s + R[lb]); } else { for (register node *now = s + L[lb]; now != s + R[lb]; ++now) if (l <= now -> id) now -> s += x; std::sort(s + L[lb], s + R[lb]); for (int i = lb + 1; i < rb; i++) tg[i] += x; for (register node *now = s + L[rb]; now != s + R[rb]; ++now) if (now -> id <= r) now -> s += x; std::sort(s + L[rb], s + R[rb]); } } else { IO::cout << query(l) << ' '; } } return 0; }