题意:给定一个序列,有两种操作
操作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;
}