uestc 我的题面最简单,快来做!(线段树区间合并)

给定一个长度为NN的序列{A}A,序列元素一开始均为0。

需要你设计数据结构并实现两种操作:

2.给出一个区间[L,R][L,R],你需要输出这个区间中最长连续等差数列的长度。

Standard Input

第一行有两个数NN,MM。代表序列长度与操作次数。

接下来M行,每行最开始有一个数opop。

如果op=0op=0,则后面有5个数L,R,a,k,pL,R,a,k,p,即第一种操作

如果op=1op=1,则后面有2个数L,RL,R,即第二种操作

Standard Output

对于每一个op == 1,输出一个数,表示最长连续等差序列长度。

Samples

InputOutput
5 3
0 1 5 2 2 2
0 3 5 4 2 4
1 1 5
3

Constraints

 

我哭了,我调了一天,觉得代码没问题,最后发现是查询空间没多加个1,很普通的区间合并的线段树题,对于问题中的操作,把它转化成维护差值序列,这样求最长等差串就是求最长相同的数串

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 1e5+9;

struct rt{
    ll lx,rx,lazy;int maxl,maxr,lmax;
}dat[maxn*4];

void pushUp(int k,int l,int r){

    dat[k].lx=dat[k<<1].lx;
    dat[k].rx=dat[k<<1|1].rx;

    int mid=(l+r)>>1;
    dat[k].maxl=dat[k<<1].maxl;
    if(dat[k<<1].maxl==(mid-l+1)&&dat[k<<1].rx==dat[k<<1|1].lx){
        dat[k].maxl=dat[k].maxl+dat[k<<1|1].maxl;
    }

    dat[k].maxr=dat[k<<1|1].maxr;
    if(dat[k<<1|1].maxr==(r-mid)&&dat[k<<1].rx==dat[k<<1|1].lx){
        dat[k].maxr=dat[k].maxr+dat[k<<1].maxr;
    }

    dat[k].lmax=max(dat[k<<1].lmax,dat[k<<1|1].lmax);
    if(dat[k<<1].rx==dat[k<<1|1].lx){
        dat[k].lmax=max(dat[k].lmax,dat[k<<1].maxr+dat[k<<1|1].maxl);
    }
}

void build(int l,int r,int k){
    if(l==r){
        dat[k].lx=dat[k].rx=0;
        dat[k].maxl=dat[k].maxr=dat[k].lmax=1;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    pushUp(k,l,r);
}

void pushDown(int k){
    dat[k<<1].lx+=dat[k].lazy;
    dat[k<<1].rx+=dat[k].lazy;
    dat[k<<1|1].rx+=dat[k].lazy;
    dat[k<<1|1].lx+=dat[k].lazy;
    dat[k<<1].lazy+=dat[k].lazy;
    dat[k<<1|1].lazy+=dat[k].lazy;
    dat[k].lazy=0;
}

void add(int a,int b,int l,int r,int k,ll x){
    if(a<=l&&r<=b){

        dat[k].lx+=x;
        dat[k].rx+=x;
        dat[k].lazy+=x;
        return ;
    }
    int mid=(l+r)>>1;
    if(dat[k].lazy)pushDown(k);
    if(a<=mid)add(a,b,l,mid,k<<1,x);
    if(b>mid)add(a,b,mid+1,r,k<<1|1,x);
    pushUp(k,l,r);
}

int query(int a,int b,int l,int r,int k){
    if(a<=l&&r<=b)return dat[k].lmax;
    if(dat[k].lazy)pushDown(k);
    int mid=(l+r)>>1;
    int lmax=0;
    if(a<=mid&&b>mid){
        int lx=min(dat[k<<1].maxr,(mid-a+1));
        int ly=min(dat[k<<1|1].maxl,(b-mid));
        if(dat[k<<1].rx==dat[k<<1|1].lx){
            lmax=max(lmax,lx+ly);
        }
    }
    if(a<=mid)lmax=max(lmax,query(a,b,l,mid,k<<1));
    if(b>mid)lmax=max(lmax,query(a,b,mid+1,r,k<<1|1));
    pushUp(k,l,r);
    return lmax;
}

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    build(1,n,1);
    int x,l,r,p;ll a,k;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&l,&r);
        if(x==0){
            scanf("%lld%lld%d",&a,&k,&p);
            add(l,l,1,n,1,a);
            add(l+1,p,1,n,1,k);
            add(p+1,r,1,n,1,-k);
            if(r+1<=n){
                add(r+1,r+1,1,n,1,-(a+k*(2*p-l-r)));
            }
        }
        else{
            if(l==r)printf("1\n");
            else printf("%d\n",query(l+1,r,1,n,1)+1);
        }
    }
    return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值