LGP12179 DerrickLo's Game 学习笔记

LGP12179 DerrickLo's Game 学习笔记

Luogu Link

题意简述

给定一个长为 \(n\) 的序列 \(A\)\(q\) 次操作:

  • 1 k x\(a_k\) 变为 \(x\)
  • 2 l r 问仅通过以下行为使区间 \([l,r]\) 变为相同的数所需要花费的最小代价。

“以下行为”指:

  1. 选择一个 \(a_p\) 使其单点加 \(1\),代价为 \(1\)
  2. 选择一个整数区间 \([l,r]\) 使其中的数都变为区间最大值。代价 \((r-l+1)^2\)

\(1\le n,q,a_i\le 2\times 10^5\)

做法解析

这道题目的 \((r-l+1)^2\) 是吓人用的。因为 \(a,b>0\) 时显然有 \((a+b)^2>a^2+b^2\),所以你发现你用 \(2\) 行为操作的区间长度最长为 \(2\)。实际上这相当于可以花费 \(4\) 的代价将某个数变为最大值。

这样我们就只关心哪些数的代价小于 \(4\) 了。显然就是和最大值差小于 \(4\) 的。这个信息可以线段树维护。

代码实现

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=2e5+5;
int N,Q,A[MaxN],Opt,X,Y;
int aaa=max(1,2);
struct SegTree{
    int ls(int u){return u<<1;}
    int rs(int u){return (u<<1)|1;}
    struct node{
        int mx,d[4];
        node(){mx=0,memset(d,0,sizeof(d));}
        friend bool operator<(node &a,node &b){return a.mx<b.mx;}
        friend node operator+(node a,node b){
            if(a<b)swap(a,b);
            int diff=a.mx-b.mx;if(diff>=4)return a;
            for(int i=0,j=diff;j<4;i++,j++)a.d[j]+=b.d[i];
            return a;
        }
        friend node& operator+=(node &a,const node &b){a=a+b;return a;}
    }t[MaxN<<2];
    void pushup(int u){t[u]=t[ls(u)]+t[rs(u)];}
    void doleaf(int u,int x){t[u].mx=x,t[u].d[0]=1;}
    void build(int u,int cl,int cr){
        if(cl==cr){doleaf(u,A[cl]);return;}int cmid=(cl+cr)>>1;
        build(ls(u),cl,cmid),build(rs(u),cmid+1,cr),pushup(u);
    }
    void update(int u,int cl,int cr,int dd,int x){
        if(cl==cr){doleaf(u,x);return;}int cmid=(cl+cr)>>1;
        dd<=cmid?update(ls(u),cl,cmid,dd,x):update(rs(u),cmid+1,cr,dd,x);
        pushup(u);
    }
    node getans(int u,int cl,int cr,int dl,int dr){
        if(dl<=cl&&cr<=dr)return t[u];
        int cmid=(cl+cr)>>1;node res;
        if(dl<=cmid)res+=getans(ls(u),cl,cmid,dl,dr);
        if(dr>cmid)res+=getans(rs(u),cmid+1,cr,dl,dr);
        return res;
    }
}SgT;
int main(){
    readis(N,Q);
    for(int i=1;i<=N;i++)readi(A[i]);
    SgT.build(1,1,N);
    for(int i=1,ans,sd;i<=Q;i++){
        readis(Opt,X,Y);
        if(Opt==1)SgT.update(1,1,N,X,Y);
        if(Opt==2){
            ans=sd=0;auto [cmx,cd]=SgT.getans(1,1,N,X,Y);
            for(int i=0;i<4;i++)ans+=i*cd[i],sd+=cd[i];
            ans+=4*((Y-X+1)-sd);writil(ans);
        }
    }
    return 0;
}
posted @ 2025-07-21 08:16  矞龙OrinLoong  阅读(4)  评论(0)    收藏  举报