Codeforces 551E GukiZ and GukiZiana 分块

题目链接

题意:给定一个序列,有两种操作

操作1、区间加权

操作2、询问序列中 a[i] == y 的数的最远距离

即:

for(int i = 0; i < n; i++)if(a[i] == y) L = i, break;

for(int i = n-1; i >= 0; i--)if(a[i]==y)R=i, break;

put(R-L);

思路:分块。

介绍一下分块思想

把区间分成 x 块,那么每块长度都为 n/x (如果n/x不能整除则最后一块长度是 n%x) 

设 y 为区间长度,即y=n/x;

我们保证每一块的区间都是有序的,即所有修改后都要排个序。

再对每块区间设置一个整体偏移量 long long b;

操作1:

查询与[l,r]相交的所有块:

if( 这一块被[l,r]完整覆盖 )

b+=val;

else 

{

暴力修改:

暴力枚举这块中的所有元素,若这个元素属于[l,r] 则 这个元素+=val

对这块排个序

(显然只有边界的2块是不会被完整覆盖的)

}

操作2:

查询每一块,因为块是有序的,所以二分一下就好了。


计算复杂度:

对于操作1:

最多查询块的数量是 x, 暴力修改的复杂度是 O( y*log(y) )

所以操作1的复杂度是 O(x + y*log(y))

对于操作2:

查询块的数量是 x, 查找块内元素是二分 : log(y)

所以操作2的复杂度是 O(x * log(y))


我们要使得 O( max(x + ylog(y), xlog(y)) 尽可能小

根据基本不等式得出 当x==y时最小

=>  n = x*y; x=y=sqrt(n);

即把序列分成sqrt(n) 块, 每块的大小为sqrt(n)

#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cstdio>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
using namespace std;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x < 0) {
		putchar('-');
		x = -x;
	}
	if (x > 9) pt(x / 10);
	putchar(x % 10 + '0');
}
typedef long long ll;
typedef pair<ll, int> pii;
const int inf = 1e9;
const int N = 5e5 + 10;
const int Block = 850;//700
int n, q;
int ansl, ansr;
ll a[N];
set<pii>::iterator it;
struct Node {
	set<pii>x;
	ll b;
	inline void add(int l, int r, int val) {
		if (r - l + 1 == (int)x.size())b += val;
		else {
			for (int i = l; i <= r; i++)
			{
				x.erase({ a[i], i });
				a[i] += val;
				x.insert({ a[i], i });
			}
		}
	}
	inline void find(ll y) {
		y -= b;
		it = x.lower_bound({ y, -inf });
		if (it == x.end() || (*it).first != y)return;
		ansl = min(ansl, (*it).second);
		it = x.upper_bound({ y, inf }); it--;
		ansr = max(ansr, (*it).second);
	}
}y[Block];
int block;
int main() {
	rd(n); rd(q);
	for (int i = 0; i < n; i++)rd(a[i]);
	block = 0;
	for (int i = 0; i < n; i += Block, block++)
		for (int j = 0; i + j < n && j < Block; j++)
		{
			y[block].x.insert({ a[i + j],i + j });
		}

	int op, l, r, val;
	while (q--) {
		rd(op);
		if (op == 1)
		{
			rd(l); rd(r); rd(val);
			l--;r--;
			for (int i = l / Block; i <= r / Block; i++)
				y[i].add(max(l, i*Block), min(r, i*Block + Block - 1), val);
		}
		else {
			rd(val);
			ansl = inf, ansr = -inf;
			for (int i = 0; i < block; i++)
				y[i].find(val);
			if (ansr - ansl < 0)puts("-1");
			else pt(ansr - ansl), putchar('\n');
		}
	}
	return 0;
}
把set改掉。。:

#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cstdio>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
using namespace std;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x < 0) {
		putchar('-');
		x = -x;
	}
	if (x > 9) pt(x / 10);
	putchar(x % 10 + '0');
}
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 1e9;
const int N = 5e5 + 10;
const int Block = 850;//700
int n, q;
int ansl, ansr;
struct Node {
	struct Point {
		ll a; int id;
		Point(ll _a = 0, ll _id = 0) :a(_a), id(_id) {}
		bool operator<(const Point&x)const {
			if (x.a != a)return a < x.a;
			return id < x.id;
		}
	}x[Block], tmp;
	ll b;
	int top;
	inline void Sort() {
		sort(x, x + top);
	}
	inline void add(int l, int r, int val) {
		if (r - l + 1 == top)b += val;
		else {
			for (int i = 0; i < top; i++)
				if (l <= x[i].id && x[i].id <= r)
				x[i].a += val;
			Sort();
		}
	}
	inline void find(ll y) {
		y -= b;
		if (y < x[0].a || x[top - 1].a < y)return;
		tmp = { y, -inf };
		int l = lower_bound(x, x + top, tmp) - x;
		if (l == top || x[l].a != y)return;
		tmp.id = inf;
		int r = lower_bound(x, x + top, tmp) - x - 1;
		ansl = min(ansl, x[l].id);
		ansr = max(ansr, x[r].id);
	}
}y[Block];
int a[N], block;
int main() {
	rd(n); rd(q);
	for (int i = 0; i < n; i++)rd(a[i]);
	block = 0;
	for (int i = 0; i < n; i += Block, block++) {
		for (int j = 0; i + j < n && j < Block; j++)
		{
			y[block].x[j].a = a[i + j];
			y[block].x[j].id = i + j;
			y[block].top++;
		}
		y[block].Sort();
	}
	int op, l, r, val;
	while (q--) {
		rd(op);
		if (op == 1)
		{
			rd(l); rd(r); rd(val);
			l--;r--;
			for (int i = l / Block; i <= r / Block; i++)
				y[i].add(max(l, i*Block), min(r, i*Block + Block - 1), val);
		}
		else {
			rd(val);
			ansl = inf, ansr = -inf;
			for (int i = 0; i < block; i++)
				y[i].find(val);
			if (ansr - ansl < 0)puts("-1");
			else pt(ansr - ansl), putchar('\n');
		}
	}
	return 0;
}



你可能感兴趣的:(Codeforces 551E GukiZ and GukiZiana 分块)