题目链接:
题目大意:
首先给出一个序列,你有两个操作:
第一个是给这个序列一个区间内的数加上一个统一的值x
第二个是求这个序列中等于y的相距最远的两个数的距离,不存在这个数的时候输出-1
题目分析:
对于这种用不了线段树的无良的区间修改查询的题,能想到的也就是分块算法,分成sqrt(n)块即可,对于每一块根据值的大小排序,值相同按照初始位置的大小排序
这么排序是有我的道理的,首先修改怎么做,先记录下每个块的左右边界,每次遍历sqrt(n)个块,看哪个块需要被修改,如果这个块全部要修改,记录下值,如果部分修改,那么没办法只能一个一个修改,这个最坏复杂度是o(n),但是并不好凑出这种数据。
然后查询就体现了分块的优势,首先每一块内都是有序的,可以进行二分查找,只需要sqrt(n)次二分查找就可以了,复杂度就是q*sqrt(n)*log(sqrt(n)),相对于十秒的时间只能说还好,这道题的最重要的是姿势,相信我,常熟都卡。。。。。醉了,这场codeforces简直憋屈到死
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define MAX 500007
using namespace std;
typedef long long LL;
struct Node
{
LL x;
int id;
int loc;
bool operator < ( const Node& a ) const
{
if ( id == a.id && x == a.x ) return loc < a.loc;
if ( id == a.id ) return x < a.x;
return id < a.id;
}
}p[MAX];
LL add[MAX];
int n,q;
int low[MAX];
int high[MAX];
int main ( )
{
int f,l,r,x;
while ( ~scanf ( "%d%d" , &n , &q ) )
{
int num = sqrt(n)+1;
int cnt = 0;
memset ( add , 0 , sizeof ( add ) );
memset ( low , -1 , sizeof( low ) );
memset ( high , -1 , sizeof ( high ));
for ( int i = 0 ; i < n ; i++ )
{
scanf ( "%lld" , &p[i].x );
p[i].id = i/num;
p[i].loc = i;
cnt = max ( cnt , i/num );
if ( low[cnt] == -1 ) low[cnt] = i;
high[cnt] = max ( high[cnt] , i );
}
cnt++;
sort ( p , p+n );
//for ( int i = 0 ; i < cnt ; i++ )
// cout << "intevial : " << i << " " <<
// low[i] << " " << high[i] << endl;
/*for ( int i = 0 ; i < n ; i++ )
printf ( "%lld " , p[i].x );
puts("");*/
while ( q-- )
{
scanf ( "%d" , &f );
if ( f == 1 )
{
scanf ( "%d%d%d" , &l , &r , &x );
l--,r--;
for ( int i = 0 ; i < cnt ; i++ )
{
if ( l <= low[i] && r >= high[i] )
add[i] += x;
else if ( low[i] > r || high[i] < l )
continue;
else
{
for ( int j = low[i]; j <= high[i] ; j++ )
if ( p[j].loc >= l && p[j].loc <= r )
p[j].x += x;
sort ( p+low[i] , p+high[i]+1);
}
}
/*for ( int i = 0 ; i < n ; i++ )
printf ( "%lld " , p[i].x );
puts("");*/
}
else
{
scanf ( "%d" , &x );
int ll=MAX,rr=-1;
for ( int i = 0 ; i < cnt ; i++ )
{
LL temp = x- add[i];
int l = low[i] , r = high[i] , mid;
while ( l != r )
{
mid = (l+r+1) >>1;
if ( p[mid].x > temp ) r = mid-1;
else l = mid;
}
if ( p[l].x == temp )
rr = max ( rr , p[l].loc );
l = low[i] , r = high[i];
while ( l != r )
{
mid = l+r>>1;
if ( p[mid].x < temp ) l = mid+1;
else r = mid;
}
if ( p[l].x == temp )
ll = min ( ll , p[l].loc );
}
if ( rr == -1 ) puts ("-1" );
else printf ( "%d\n" , rr-ll );
}
}
}
}