LGP12263 [STAOI R9] 回听 学习笔记

LGP12263 [STAOI R9] 回听 学习笔记

Luogu Link

题意简述

给定一个长为 \(n\) 的数组 \(A\)

定义“回听”操作为:选择一系列 \(n\) 以内的下标,记该下标集合为 \(S\)。令所有 \(a_{s_i}\) 去到 \(s_{i+1}\) 位置。特别的,令 \(a_{s_{|S|}}\) 去到 \(s_1\) 位置并减掉 \(|S|-1\)(但不能减到 \(0\) 以下)。

定义 \(b_i\) 为一次回听操作后 \(a_i\) 可能产生的最小值。

\(m\) 次对 \(A\) 的区间加修改。在每次修改后回答有多少种 \(b_i\) 取值。

\(n,m\le 5\times 10^5\)\(V\) 经过区间加后会到达long long范围。

做法解析

手玩,你发现:\(b_i\) 要么是 \(j\in[1,i]\) 内最小的 \(a_j\),要么是对于 \(j\in(i,n]\) 最小的 \(a_i-(j-i)\)。如果你只是想单点求 \(b_i\),两个区间加区间最小值的线段树就能搞定。

但是“本质不同的 \(b_i\)”又要怎么搞?这东西复杂度看着就很不简单啊,除非……

除非“本质不同”是个幌子。你分析一下这个东西。你发现,\(b_i\)\(i\) 增加单调不降,并且相邻 \(b_i\) 间差值最多为 \(1\)。这意味着你求出 \(b_1\)\(b_n\) 之后,本质不同的 \(b_i\) 种数就是 \(b_n-b_1+1\)

为什么呢?这是因为随着 \(i\) 每增加 \(1\),你发现来源于 \((i,n]\) 的那部分答案就会随之增加 \(1\),而来源于 \([1,i]\) 的那部分答案不变。

好说完了。

代码实现

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=5e5+5;
const lolo Inf=1e18;
int N,M,A[MaxN],D[MaxN],X,Y,Z;
struct SegTree{
    lolo mn[MaxN<<2],tag[MaxN<<2];
    int ls(int u){return u<<1;}
    int rs(int u){return (u<<1)|1;}
    void pushup(int u){mn[u]=min(mn[ls(u)],mn[rs(u)]);}
    void build(int u,int cl,int cr,int x[]){
        if(cl==cr){mn[u]=x[cl];return;}int cmid=(cl+cr)>>1;
        build(ls(u),cl,cmid,x),build(rs(u),cmid+1,cr,x),pushup(u);
    }
    void maketag(int u,lolo x){mn[u]+=x,tag[u]+=x;}
    void pushdown(int u){if(tag[u])maketag(ls(u),tag[u]),maketag(rs(u),tag[u]),tag[u]=0;}
    void update(int u,int cl,int cr,int dl,int dr,lolo x){
        if(dl<=cl&&cr<=dr){maketag(u,x);return;}
        int cmid=(cl+cr)>>1;pushdown(u);
        if(dl<=cmid)update(ls(u),cl,cmid,dl,dr,x);
        if(dr>cmid)update(rs(u),cmid+1,cr,dl,dr,x);
        pushup(u);
    }
    lolo getmin(int u,int cl,int cr,int dl,int dr){
        if(dl<=cl&&cr<=dr)return mn[u];
        int cmid=(cl+cr)>>1;lolo res=Inf;pushdown(u);
        if(dl<=cmid)minner(res,getmin(ls(u),cl,cmid,dl,dr));
        if(dr>cmid)minner(res,getmin(rs(u),cmid+1,cr,dl,dr));
        return res;
    }
}SgT1,SgT2;
int solve(int p){return min(SgT1.getmin(1,1,N,1,p),max((SgT2.getmin(1,1,N,p,N)+p),0ll));}
int main(){
    readis(N,M);
    for(int i=1;i<=N;i++)readi(A[i]),D[i]=A[i]-i;
    SgT1.build(1,1,N,A),SgT2.build(1,1,N,D);
    for(int i=1;i<=M;i++){
        readis(X,Y,Z);
        SgT1.update(1,1,N,X,Y,Z);
        SgT2.update(1,1,N,X,Y,Z);
        writil(solve(N)-solve(1)+1);
    }
    return 0;
}
posted @ 2025-07-22 11:51  矞龙OrinLoong  阅读(8)  评论(0)    收藏  举报