P7334 [JRKSJ R1] 吊打

Link

Sol:

这题需要干两个操作,区间开方和区间平方。

区间开方我们熟悉,P4145 上帝造题的七分钟 2 / 花神游历各国,这题就是区间开方求和,不难发现我们无法对整个区间进行操作,因为开方没有区间操作性,只递归能到单点去开方,要是都这么搞肯定 T 掉,但是因为开方操作能使数下降的很快,\(10^{12}\)\(6\) 次方就能降到 \(1\),并且 \(1\) 开方完还是 \(1\),所以根据这个我们可以考虑维护一个区间最大值。如果区间的最大值是 \(1\) 则无需继续下传。否则下传到单点修改。

区间平方乍一看没有什么维护的头绪,因为开方有 \(1\) 的下限,平方则没有。但是平方和开方是互逆操作,所以一次开方操作能抵消一次平方操作,记录一个 \(cnt\) ,表示该点被平方的次数,那么平方时直接丢给 \(cnt\)\(lazy\_tag\) 即可,那么开方操作也会得到优化,只要区间被平方过即 \(cnt \ge 1\) 时,修改 \(cnt\) 无需下传。

根据欧拉降幂公式:\(A^K \equiv A^{K \bmod \varphi(Mod)+\varphi(Mod)} \bmod Mod\)

又因为一个质数 \(x\)\(\varphi(x)\) 等于 \(x-1\)

\(i\) 为叶子节点,则最终答案为:\(\displaystyle \sum_{}^{}tree[i].Max^{2^{tree[i].cnt} \bmod Mod-1 +Mod-1}\bmod Mod\)

Code:

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

const int INF=0x3f3f3f3f;
const int Mod=998244353;
const int N=1e6+6;

int read() {
    int x=0,f=0;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) f|=(ch=='-');
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch&15);
    return f?-x:x;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(x>9) print(x/10);
    putchar(x%10+48);
}

int a[N],n,q;
namespace Seg{
    #define lson pos<<1
    #define rson pos<<1|1
    
    struct Tree{int Max,cnt,lazy;}tree[N];
    
    int Fast_pow(int a,int b,int mod){ int res=1;
        for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=(res*a)%mod;
        return res;
    }
        
    void push_up(int pos){
        tree[pos].cnt=min(tree[lson].cnt,tree[rson].cnt);
        tree[pos].Max=max(tree[lson].Max,tree[rson].Max);
    }
    
    void build(int pos,int l,int r){
        if(l==r) return tree[pos]=(Tree){a[l],0,0},void();
        int mid=l+r>>1;build(lson,l,mid);build(rson,mid+1,r);
        push_up(pos);return;
    }
    
    void push_down(int pos){
        if(!tree[pos].lazy) return;
        tree[lson].lazy+=tree[pos].lazy;
        tree[rson].lazy+=tree[pos].lazy;
        tree[lson].cnt+=tree[pos].lazy;
        tree[rson].cnt+=tree[pos].lazy;
        tree[pos].lazy=0; 
    } 
    
    void change_sqrt(int pos,int l,int r,int L,int R){
        if(l>R||r<L||tree[pos].Max==1) return;
        if(l>=L&&r<=R&&tree[pos].cnt>=1) return tree[pos].cnt--,tree[pos].lazy--,void();
        if(l==r) return tree[pos].Max=sqrt(tree[pos].Max),void();push_down(pos);int mid=l+r>>1;
        if(L<=mid) change_sqrt(lson,l,mid,L,R);if(R>mid) change_sqrt(rson,mid+1,r,L,R);
        push_up(pos);
    }
    
    void change_square(int pos,int l,int r,int L,int R){
        if(l>R||r<L) return;
        if(l>=L&&r<=R) return tree[pos].cnt++,tree[pos].lazy++,void();
        int mid=l+r>>1;push_down(pos);
        if(L<=mid) change_square(lson,l,mid,L,R);
        if(R>mid) change_square(rson,mid+1,r,L,R);
        push_up(pos);
    } 
    
    int Query(int pos,int l,int r){
        if(l==r) return Fast_pow(tree[pos].Max,Fast_pow(2,tree[pos].cnt,Mod-1)+Mod-1,Mod);
        int mid=l+r>>1;push_down(pos);
        return (Query(lson,l,mid)+Query(rson,mid+1,r))%Mod;
    }
    #undef lson 
    #undef rson 
}

signed main() {
   n=read();q=read();
   for(int i=1;i<=n;i++)a[i]=read();
   Seg::build(1,1,n);
   while(q--){
       int opt=read(),l=read(),r=read();
       if(opt&1) Seg::change_sqrt(1,1,n,l,r);
       else Seg::change_square(1,1,n,l,r);
   }
   return print(Seg::Query(1,1,n)),0;
}
posted @ 2022-05-12 15:03  Gym_nastics  阅读(83)  评论(0编辑  收藏  举报