【题解】P11334 [NOISG 2020 Finals] Progression

P11334 [NOISG 2020 Finals] Progression

题意

给定长度为 \(n\) 的序列,进行 \(m\) 次操作或询问:

  • 区间加等差数列
  • 区间设等差数列
  • 查询区间内最长等差数列长度

题解

知识点:线段树,差分。

启发:

  • 原数组转差分数组方便操作。

  • 一种信息合并的技巧。

难写又难调。

看到一堆等差,果断先将原数组差分。

那么 \([l,r]\) 的最长等差数列长度其实就是差分数组的 \([l+1,r]\) 的最长颜色段长度加一。

在差分数组上,\([l,r]\) 加等差数列就变成了区间加问题,而设等差数列则是区间推平,这两个操作用线段树可以轻易实现,不过千万不能忘了第 \((r+1)\) 位置也要修改。

现在考虑 push_up 的实现,对每个结点分别维护从左端点开始、从右端点开始以及整体的最长颜色段,那么合并的方法就很显然了,对着维护区间最大子段和的方法照葫芦画瓢即可。

整体思路就这么简单,这题主要是代码较为难写。

#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()

#define N 302505
#define int long long

int n,m,a[N];

struct SEG{
    #define mid ((l+r)>>1)

    int add[N<<2],col[N<<2];
    bitset<N<<2>cc;

    struct node{
        pr p,l,r;
        int len,sum;

        node(){
            len=0;
            p=l=r={0,0};
        }
    }tr[N<<2];

    inline node un(node x,node y){
        node g;

        g.l=x.l;
        g.r=y.r;
        g.p=max(x.p,y.p);
        g.len=x.len+y.len;
        g.sum=x.sum+y.sum;

        if(x.r.se==y.l.se){
            g.p=max(g.p,{x.r.fi+y.l.fi,x.r.se});
        }

        if(x.l.fi==x.len&&x.l.se==y.l.se){
            g.l=max(g.l,{x.l.fi+y.l.fi,x.l.se});
        }

        if(y.r.fi==y.len&&y.r.se==x.r.se){
            g.r=max(g.r,{y.r.fi+x.r.fi,y.r.se});
        }

        g.p=max({g.p,g.l,g.r});

        return g;
    }

    inline void t_add(int k,int l,int r,int d){
        add[k]+=d;
        tr[k].sum+=d*(r-l+1);

        tr[k].p.se+=d;
        tr[k].l.se+=d;
        tr[k].r.se+=d;
    }

    inline void t_col(int k,int l,int r,int d){
        add[k]=0;
        col[k]=d;
        cc[k]=1;

        tr[k].sum=d*(r-l+1);
        tr[k].p=tr[k].l=tr[k].r={r-l+1,d};
    }

    inline void pd(int k,int l,int r){
        if(cc[k]){
            t_col(k*2,l,mid,col[k]);
            t_col(k*2+1,mid+1,r,col[k]);

            col[k]=0;
            cc[k]=0;
        }

        if(add[k]){
            t_add(k*2,l,mid,add[k]);
            t_add(k*2+1,mid+1,r,add[k]);
            add[k]=0;
        }
    }

    inline void build(int k,int l,int r){
        add[k]=0;
        col[k]=0;
        cc[k]=0;

        if(l==r){
            tr[k].p=tr[k].l=tr[k].r={1,a[l]};
            tr[k].len=1;
            tr[k].sum=a[l];

            return;
        }

        build(k*2,l,mid);
        build(k*2+1,mid+1,r);

        tr[k]=un(tr[k*2],tr[k*2+1]);
    }

    inline void upd_add(int L,int R,int k,int l,int r,int d){
        if(L>R){
            return;
        }

        if(L<=l&&R>=r){
            t_add(k,l,r,d);
            return;
        }

        pd(k,l,r);

        if(L<=mid){
            upd_add(L,R,k*2,l,mid,d);
        }
        if(R>mid){
            upd_add(L,R,k*2+1,mid+1,r,d);
        }

        tr[k]=un(tr[k*2],tr[k*2+1]);
    }

    inline void upd_col(int L,int R,int k,int l,int r,int d){
        if(L>R){
            return;
        }

        if(L<=l&&R>=r){
            t_col(k,l,r,d);
            return;
        }

        pd(k,l,r);

        if(L<=mid){
            upd_col(L,R,k*2,l,mid,d);
        }
        if(R>mid){
            upd_col(L,R,k*2+1,mid+1,r,d);
        }

        tr[k]=un(tr[k*2],tr[k*2+1]);
    }

    inline node ask(int L,int R,int k,int l,int r){
        if(L>R){
            node sb;
            return sb;
        }

        if(L<=l&&R>=r){
            return tr[k];
        }

        pd(k,l,r);

        node ls,rs;

        if(L<=mid){
            ls=ask(L,R,k*2,l,mid);
        }
        if(R>mid){
            rs=ask(L,R,k*2+1,mid+1,r);
        }

        return un(ls,rs);
    }

    inline int sum(int L,int R,int k,int l,int r){
        if(L>R){
            return 0;
        }

        if(L<=l&&R>=r){
            return tr[k].sum;
        }

        pd(k,l,r);

        int ans=0;

        if(L<=mid){
            ans+=sum(L,R,k*2,l,mid);
        }
        if(R>mid){
            ans+=sum(L,R,k*2+1,mid+1,r);
        }
        
        return ans;
    }

    #undef mid
}t;

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);

    cin>>n>>m;

    rep(i,1,n){
        cin>>a[i];
    }

    per(i,1,n){
        a[i]-=a[i-1];
    }

    t.build(1,1,n);

    rep(i,1,m){
        int op,l,r,s,c;
        cin>>op>>l>>r;

        if(op==1){
            cin>>s>>c;

            int pre=0;
            if(r+1<=n){
                pre=t.sum(1,r+1,1,1,n);
            }
            
            t.upd_add(l,l,1,1,n,s);
            t.upd_add(l+1,r,1,1,n,c);

            if(r+1<=n){
                t.upd_col(r+1,r+1,1,1,n,pre-t.sum(1,r,1,1,n));
            }
        }

        if(op==2){
            cin>>s>>c;

            int pre=0;
            if(r+1<=n){
                pre=t.sum(1,r+1,1,1,n);
            }

            int tmp=s-t.sum(1,l-1,1,1,n);

            t.upd_col(l,l,1,1,n,tmp);
            t.upd_col(l+1,r,1,1,n,c);

            if(r+1<=n){
                t.upd_col(r+1,r+1,1,1,n,pre-t.sum(1,r,1,1,n));
            }
        }

        if(op==3){
            cout<<t.ask(l+1,r,1,1,n).p.fi+1<<"\n";
        }
    }

    return 0;
}
posted @ 2025-05-21 13:31  Lucyna_Kushinada  阅读(21)  评论(0)    收藏  举报