题目链接:

不卡常数大家还是好朋友

题目大意:

首先给出一个序列,你有两个操作:

第一个是给这个序列一个区间内的数加上一个统一的值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 );
            }
        }
    }
}