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