LGP8969 幻梦 Dream with Dynamic

LGP8969 幻梦 Dream with Dynamic

\(\texttt{Luogu Link}\)

前言

唉,强校。

抛开别的不谈,这题意外地好懂……吗?

本学习笔记解析部分抄袭此文,代码抄袭此文

题意简述

有一个长度为 \(n\) 的序列 \(A\),有初值。需支持三种操作共 \(m\) 次:

  • A l r x\(\forall i\in [l,r]\)\(a_i\gets a_i+x\)
  • P l r\(\forall i\in [l,r]\)\(a_i\gets \text{ppc}(a_i)\)
  • J u:查询 \(a_u\) 的值。

\(n\le 3\times 10^5\)\(q\le 10^6\)\(a_i,x\le 10^9\)

做法解析

看起来和有些势能线段树很像?然而这题的势能没什么良好性质。那咋办。

但是 \(\text{ppc}\) 有非常良好的性质。它的值域只有 \(\log V\)。怎么用呢?

首先我们查询只有单点的,这两种修改在线段树上成区间地作用是简单的。所以我们思考单点受到的操作就行了。

我们来把操作序列写出来:\(\texttt{apapppaaaapaapa}\)

连串的加法是容易复合的,不妨把它们缩到一段,再按 \(\texttt{p}\) 割开操作序列:

\(\texttt{ap|ap|p|p|ap|ap|a}\)。这是若干个 \(\text{ppc}(x+b)\to x'\) 的复合,满足 \(x,x'\) 值域和定义域都在 \(\log V\) 范围(除了最开始的 \(x\))。我们对于 \(w\in [0,\log V]\),维护 \(F(w)=f_k(f_{k-1}(f_{k-2}(\dots f_3(f_2(f_1(w)))\dots)))\) 的值,其中 \(f_i(w)\) 为第一个 \(\text{ppc}\) 操作之后的第 \(i\)\(\text{ppc}(x+b)\to x'\)。由于 \(w\) 只有 \(O(\log V)\) 种情况,所以我们可以暴力维护 \(w\) 取所有值时的情况,\(O(m\log V)\) 可以接受。最后查询时就输出 \(F(f_0(a_u))\) 即可。

当然,还要另外特殊处理一下没有 \(\text{ppc}\) 的情况。

代码实现

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=3e5+5,MaxVb=51;
int N,M,A[MaxN],X,Y,Z;char Opt;
struct adat{int o;lolo d,b[MaxVb];};
adat addion(adat t,lolo x){
    if(t.o==0)t.d+=x;
    else for(int i=0;i<=50;i++)t.b[i]+=x;
    return t;
}
adat ppcion(adat t){
    if(t.o==0)for(int i=0;i<=50;i++)t.b[i]=i;
    else for(int i=0;i<=50;i++)t.b[i]=__builtin_popcountll(t.b[i]);
    t.o=1;return t;
}
adat merge(adat x,adat y){
    if(y.o==0)return addion(x,y.d);
    if(x.o==0){y.d+=x.d;return y;}
    for(int i=0;i<=50;i++)x.b[i]=y.b[__builtin_popcountll(x.b[i]+y.d)];
    return x;
}
struct SegTree{
    adat t[MaxN<<2];
    int cl[MaxN<<2],cr[MaxN<<2],cmid[MaxN<<2];
    int ls(int u){return u<<1;}
    int rs(int u){return (u<<1)|1;}
    void build(int u,int l,int r){
        cl[u]=l,cr[u]=r;if(l==r)return;
        int mid=(l+r)>>1;cmid[u]=mid;
        build(ls(u),l,mid),build(rs(u),mid+1,r);
    }
    void pushdown(int u){
        t[ls(u)]=merge(t[ls(u)],t[u]);
        t[rs(u)]=merge(t[rs(u)],t[u]);
        t[u].o=t[u].d=0;
    }
    void addupd(int u,int dl,int dr,int x){
        if(dl<=cl[u]&&cr[u]<=dr){t[u]=addion(t[u],x);return;}
        pushdown(u);
        if(dl<=cmid[u])addupd(ls(u),dl,dr,x);
        if(dr>cmid[u])addupd(rs(u),dl,dr,x);
    }
    void ppcupd(int u,int dl,int dr){
        if(dl<=cl[u]&&cr[u]<=dr){t[u]=ppcion(t[u]);return;}
        pushdown(u);
        if(dl<=cmid[u])ppcupd(ls(u),dl,dr);
        if(dr>cmid[u])ppcupd(rs(u),dl,dr);
    }
    adat query(int u,int dd){
        if(cl[u]==cr[u])return t[u];
        pushdown(u);return query(dd<=cmid[u]?ls(u):rs(u),dd);
    }
}SgT;
int main(){
    readis(N,M);SgT.build(1,1,N);
    for(int i=1;i<=N;i++)readi(A[i]);
    for(int i=1;i<=M;i++){
        scanf(" %c",&Opt);
        if(Opt=='A')readis(X,Y,Z),SgT.addupd(1,X,Y,Z);
        if(Opt=='P')readis(X,Y),SgT.ppcupd(1,X,Y);
        if(Opt=='J'){
            readi(X);adat res=SgT.query(1,X);
            if(res.o==0)writil(A[X]+res.d);
            else writil(res.b[__builtin_popcountll(A[X]+res.d)]);
        }
    }
    return 0;
}
posted @ 2025-10-22 13:57  矞龙OrinLoong  阅读(5)  评论(0)    收藏  举报