Professor GukiZ was playing with arrays again and accidentally discovered new function, which he called GukiZiana. For given array a, indexed with integers from 1 to n, and number y, GukiZiana(a, y) represents maximum value of j - i, such that aj = ai = y. If there is no y as an element in a, then GukiZiana(a, y) is equal to - 1. GukiZ also prepared a problem for you. This time, you have two types of queries:
- First type has form 1 l r x and asks you to increase values of all ai such that l ≤ i ≤ r by the non-negative integer x.
- Second type has form 2 y and asks you to find value of GukiZiana(a, y).
For each query of type 2, print the answer and make GukiZ happy!
The first line contains two integers n, q (1 ≤ n ≤ 5 * 105, 1 ≤ q ≤ 5 * 104), size of array a, and the number of queries.
The second line contains n integers a1, a2, ... an (1 ≤ ai ≤ 109), forming an array a.
Each of next q lines contain either four or two numbers, as described in statement:
If line starts with 1, then the query looks like 1 l r x (1 ≤ l ≤ r ≤ n, 0 ≤ x ≤ 109), first type query.
If line starts with 2, then th query looks like 2 y (1 ≤ y ≤ 109), second type query.
For each query of type 2, print the value of GukiZiana(a, y), for y value for that query.
4 3
1 2 3 4
1 1 2 1
1 1 1 1
2 3
2
2 3
1 2
1 2 2 1
2 3
2 4
0
-1
题意:给你一个n个数的序列,以及q个操作,有两种操作,1是区间[l,r]上的每个数加上v 2是查询y,求aj = ai = y的最大j-i
思路:我想到分块的做法,分为tb块,每一块中的每个元素保存v和id,然后每一块按v排序,相等按id排序,这样对于查询的时候,我们只需要从左到右找到第一块满足存在y,那么pl = lowwer_bound(y)。同理从右到左找到第一块满足存在y,那么pr = upper_bound(y)。 答案就是pr-pl。
对于更新操作,区间[l,r]所覆盖的块中,第一块和最后一块暴力更新,并且重建块,即重新排序。而对于中间的完整覆盖的块,我们只记录增量add[b],因为add[b]表示b整块的增量,那么b快依然有序,在b块查询x的时候,x -= add[b]即可。
做法很快想好了,但wa了好多发,就是以为不会爆ll。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5e5 + 10; const int SIZE = 571; struct Block { ll v; int id; Block() {} Block(ll v, int id) : v(v), id(id) {} friend bool operator < (Block a, Block b) { if(a.v == b.v) return a.id < b.id; return a.v < b.v; }; }; Block block[N/SIZE + 1][SIZE + 1]; int n, q; ll A[N]; ll add[N/SIZE + 1]; int tb, ls; void init() { scanf("%d%d", &n, &q); int b = 0, j = 0; for(int i = 0; i < n; ++i) { scanf("%I64d", &A[i]); block[b][j] = Block(A[i], i); if(++j == SIZE) { b++; j = 0;} } ls = 0; for(int i = 0; i < b; ++i) sort(block[i], block[i] + SIZE); if(j) { ls = j; sort(block[b], block[b] + j); } tb = b; } void rebuild(int b, int sz) { int j = 0; for(int i = b * SIZE; i < b * SIZE + sz; ++i) block[b][j++] = Block(A[i], i); sort(block[b], block[b] + j); } void update(int L, int R, int v) { int lb = L / SIZE, rb = R / SIZE, j, sz; if(lb == rb) { for(int i = L; i <= R; ++i) A[i] += v; if(lb == tb) sz = ls; else sz = SIZE; rebuild(lb, sz); }else { for(int i = L; i < (lb + 1) * SIZE; ++i) A[i] += v; rebuild(lb, SIZE); for(int i = rb * SIZE; i <= R; ++i) A[i] += v; if(rb == tb) sz = ls; else sz = SIZE; rebuild(rb, sz); for(int b = lb + 1; b < rb; ++b) add[b] += v; } } int upper(Block a[], int sz, ll v) { int L = 0, R = sz; while(R - L > 1) { int M = (L + R) >> 1; if(a[M].v <= v) L = M; else R = M; } return L; } int lower(Block a[], int sz, ll v) { int L = 0, R = sz; while(L < R) { int M = (L + R) >> 1; if(a[M].v >= v) R = M; else L = M + 1; } return L; } int query(ll x) { int pl = -1, pr = -1; ll v; if(tb == 0) { for(int i = 0; i < ls; ++i) if(A[i] == x) { pl = i; break; } for(int i = ls - 1; i >= 0; --i) if(A[i] == x) { pr = i; break; } if(pl == -1) return -1; }else { if(ls) for(int i = tb * SIZE + ls - 1; i >= tb * SIZE; --i) if(A[i] == x) { pr = i; break; } if(pr == -1) { for(int b = tb - 1; b >= 0; --b) { v = x - add[b]; int px = upper(block[b], SIZE, v); if(px < SIZE && block[b][px].v == v) { pr = block[b][px].id; break; } } } if(pr == -1) return -1; for(int b = 0; b < tb; ++b) { v = x - add[b]; int pi = lower(block[b], SIZE, v); if(pi < SIZE && block[b][pi].v == v) { pl = block[b][pi].id; break; } } if(pl == -1) { for(int i = tb * SIZE; i < tb * SIZE + ls; ++i) if(A[i] == x) { pl = i; break; } } } return pr - pl; } int main() { //freopen("in.txt", "r", stdin); init(); int op, l, r, x; memset(add, 0, sizeof add); for(int i = 0; i < q; ++i) { scanf("%d", &op); if(op == 1) { scanf("%d%d%d", &l, &r, &x); l--; r--; update(l, r, x); }else { scanf("%d", &x); printf("%d ", query(x)); } } return 0; }