2023北航校赛-K线段树

link:https://codeforces.com/gym/104880
题意:给一序列,需要支持操作:1、区间开方并下取整。2、区间平方。3、单点查询。\(1\leq n,q\leq 2\times 10^5\)


刚看到题的时候还是感觉眼前一亮的hhh,区间开方+区间查询是个经典的势能线段树问题,但如果加上平方还能不能做呢,区间查询就很难支持了,但这题要的是单点查询。

想一下区间平方完了再开方(并下取整),相当于没做。我用 \(S\) 表示一次开方操作, \(P\) 表示一次平方操作,我们初步认识下会觉得,每个位置的操作序列是任意一个 \(\{S,P\}\) 构成的序列,但现在我们发现一旦出现 \(PS\) 就可以立马消掉,那么如果有一段连续的 \(P\) 遇到一个 \(S\) 就只会少一个 \(P\),反过来如果 \(S\) 在前 \(P\) 在后,其后也不可能有新的 \(S\),操作序列只能是形如 \(S^ x P^y\) 的形式,那么我们就可以对每个区间维护几次开方、几次平方,对于线段树来说,只需要在标记下放的时候合并就行(不要忘记 push_down 本身就带有时间的信息,标记下传之前的信息必然已经合并过了,所以不需要担心这个)

这题能看得出一个一般矛盾到特殊矛盾的转化,如果是随便的两种操作混合在一起,要做查询是很困难的,但这里的特殊性在于,题目选择了互相对立的两个操作:开方和平方

实现: 写这题的时候因为忘记push_down 花了些时间debug,怎么写了这么久线段树还是会忘记写啊!!
以及一开始写一直平方的操作想省掉快速幂,结果写错了偷懒失败…

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+5;
const int MOD=1e9+7;
int n,q,a[N],P[N<<2],S[N<<2];
int ksm(int a,int b,int MOD){
    int ret=1;
    for(;b;b>>=1,a=(ll)a*a%MOD)if(b&1)ret=(ll)ret*a%MOD;
    return ret;
}
#define ls (node<<1)
#define rs (node<<1|1)
void push_down(int node){
    if(!P[node]&&!S[node])return;
    if(P[ls]>=S[node]){
        P[ls]-=S[node];
        P[ls]+=P[node];
    }else{
        int t=S[node]-P[ls];
        P[ls]=0;
        S[ls]+=t;
        P[ls]=P[node];
    }
    if(P[rs]>=S[node]){
        P[rs]-=S[node];
        P[rs]+=P[node];
    }else{
        int t=S[node]-P[rs];
        P[rs]=0;
        S[rs]+=t;
        P[rs]=P[node];
    }
    P[node]=S[node]=0;
}
void modify(int node,int l,int r,int ql,int qr,int v){
    if(ql<=l&&r<=qr){
        if(v==0){//S
            if(P[node])P[node]--;
            else S[node]++;
        }else{//P
            P[node]++;
        }
        return;
    }
    push_down(node);
    int mid=(l+r)>>1;
    if(mid>=ql)modify(ls,l,mid,ql,qr,v);
    if(mid+1<=qr)modify(rs,mid+1,r,ql,qr,v);
}
int query(int node,int l,int r,int x){
    if(l==r){
        // cout<<"query on "<<node<<' '<<l<<' '<<r<<' '<<P[node]<<' '<<S[node]<<endl;
        int val=a[l];
        rep(i,1,min(32,S[node]))val=(int)sqrt(val);
        return ksm(val,ksm(2,P[node],MOD-1),MOD);
        // return ret;
    }
    push_down(node);
    int mid=(l+r)>>1;
    if(mid>=x)return query(ls,l,mid,x);
    return query(rs,mid+1,r,x);
}

int main(){
    fastio;
    cin>>n>>q;
    rep(i,1,n)cin>>a[i];
    while(q--){
        int op,l,r,x;
        cin>>op;
        if(op==1){
            cin>>l>>r;
            modify(1,1,n,l,r,0);
        }else if(op==2){
            cin>>l>>r;
            modify(1,1,n,l,r,1);
        }else{
            cin>>x;
            cout<<query(1,1,n,x)<<endl;
        }
        // rep(i,1,n)cout<<query(1,1,n,i)<<' ';cout<<endl;
    }
    return 0;
}
posted @ 2024-04-05 02:04  yoshinow2001  阅读(3)  评论(0编辑  收藏  举报