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