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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章