2023北航校賽-K線段樹

yoshinow2001發表於2024-04-05

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;
}

相關文章