[Codeforces551E]GukiZ and GukiZiana(分块)

16 篇文章 0 订阅

题目描述

传送门
题意:
1 l r x 将区间[l,r]的元素都+x
2 y 查询序列中是y这个数的坐标的最大差值

题解

分块之后对每一块排序然后每次查询的时候二分就行了
每一块维护一个add,整块打标记,剩余暴力修改

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
#define N 500005

int n,m,opt,l,r,block,t,ans;
int L[N],R[N];
LL x,y;
LL a[N],b[N],add[N];

void init(int id)
{
    for (int i=L[id];i<=R[id];++i) b[i]=a[i];
    sort(b+L[id],b+R[id]+1);
}
void change(int l,int r,LL x)
{
    int numl=(l-1)/block+1,numr=(r-1)/block+1;
    if (numl==numr)
    {
        for (int i=l;i<=r;++i) a[i]+=x;
        init(numl);
        return;
    }
    if (l==L[numl]) l=numl;
    else
    {
        for (int i=l;i<=R[numl];++i) a[i]+=x;
        init(numl);
        l=numl+1;
    }
    if (r==R[numr]) r=numr;
    else
    {
        for (int i=L[numr];i<=r;++i) a[i]+=x;
        init(numr);
        r=numr-1;
    }
    for (int i=l;i<=r;++i) add[i]+=x;
}
int find(int l,int r,LL x)
{
    while (l<=r)
    {
        int mid=(l+r)>>1;
        if (b[mid]==x) {return mid;}
        else if (b[mid]>x) r=mid-1;
        else l=mid+1;
    }
    return -1;
}
int query(LL y)
{
    int ansl=n,ansr=0;
    for (int i=1;i<=t;++i)
    {
        int loc=find(L[i],R[i],y-add[i]);
        if (loc==-1) continue;
        for (int j=L[i];j<=R[i];++j)
            if (a[j]+add[i]==y) {ansl=j;break;}
        break;
    }
    for (int i=t;i>=1;--i)
    {
        int loc=find(L[i],R[i],y-add[i]);
        if (loc==-1) continue;
        for (int j=R[i];j>=L[i];--j)
            if (a[j]+add[i]==y) {ansr=j;break;}
        break;
    }
    if (ansl>ansr) return -1;
    return ansr-ansl;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i) scanf("%I64d",&a[i]);
    block=sqrt(n);t=(n-1)/block+1;
    L[1]=1,R[1]=block;
    for (int i=2;i<=t;++i) L[i]=L[i-1]+block,R[i]=R[i-1]+block;R[t]=n;
    for (int i=1;i<=t;++i) init(i);
    for (int i=1;i<=m;++i)
    {
        scanf("%d",&opt);
        if (opt==1)
        {
            scanf("%d%d%I64d",&l,&r,&x);
            if (l>r) swap(l,r);
            change(l,r,x);
        }
        else
        {
            scanf("%I64d",&y);
            ans=query(y);
            printf("%d\n",ans);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值