[CF551E]GukiZ and GukiZiana

题目大意:一个长度为$n(n\leqslant5\times10^5)$的数组,有两个操作:

  1. $1\;l\;r\;x:$把区间$[l,r]$加上$x$
  2. $2\;x:$询问$x$第一次出现和最后一次出现之间的距离,若没出现输出$-1$

题解:分块,把每个块排个序(可以把数值为第一关键字,位置为第二关键字),整块的加就块上打$tag$,非整块的就暴力重构,查询就在每个块内求这个数出现位置,直接二分查找就行了。设块大小为$S$,修改复杂度$O(\dfrac n S+2S)$,查询复杂度$O(\dfrac n S\log_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) << '\n';
		}
	}
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/10135735.html