参考:http://blog.csdn.net/discreeter/article/details/78184803
题目:
https://vjudge.net/problem/CodeForces-551E
题意:
给定一个长度为n的序列a,有两种操作:
1 l r x:把区间[l,r]内的元素都加上x
2 y:查询整个序列中值为y的元素的最远距离,若没有y输出−1
心得:
这个奇怪的询问方式一般只能分块来解决了..
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 500000 + 10, INF = 0x3f3f3f3f;
int L[N], R[N], pos[N];
int sz, block;
LL a[N], b[N], add[N];
void reset(int x) {
for(int i = L[x]; i <= R[x]; i++) b[i] = a[i];
sort(b + L[x], b + 1 + R[x]);
}
void init(int n) {
block = (int)sqrt(n);
sz = n / block;
if(n % block) sz++;
for(int i = 1; i <= n; i++) pos[i] = (i-1) / block + 1;
for(int i = 1; i <= sz; i++) {
L[i] = (i-1) * block + 1;
R[i] = i * block;
}
R[sz] = n;
for(int i = 1; i <= sz; i++) reset(i);
memset(add, 0, sizeof add);
}
void update(int l, int r, int val) {
int lb = pos[l], rb = pos[r];
if(lb == rb) {
for(int i = l; i <= r; i++) a[i] += val;
reset(lb);
}
else {
for(int i = l; i <= R[lb]; i++) a[i] += val;
for(int i = L[rb]; i <= r; i++) a[i] += val;
for(int i = lb+1; i < rb; i++) add[i] += val;
reset(lb); reset(rb);
}
}
int query(LL val) {
int x = 0, y = 0;
for(int i = 1; i <= sz; i++)
if(binary_search(b + L[i], b + 1 + R[i], val - add[i])) {
for(int j = L[i]; j <= R[i]; j++)
if(a[j] + add[i] == val)
{
x = j; break;
}
break;
}
for(int i = sz; i >= 1; i--)
if(binary_search(b + L[i], b + 1 + R[i], val - add[i])) {
for(int j = R[i]; j >= L[i]; j--)
if(a[j] + add[i] == val)
{
y = j; break;
}
break;
}
if(!x && !y) return -1;
else return y - x;
}
int main() {
int n, m;
while(~ scanf("%d%d", &n, &m)) {
for(int i = 1; i <= n; i++) scanf("%LL", &a[i]);
init(n);
int opt, x, y, z;
for(int i = 1; i <= m; i++) {
scanf("%d", &opt);
if(opt == 1) {
scanf("%d%d%d", &x, &y, &z);
update(x, y, z);
}
else {
scanf("%d", &x);
printf("%d\n", query(x));
}
}
}
}