Codeforces Round #675 (Div. 2) 1442 F - Boring Queries 可持久化線段樹維護 區間乘法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define pb push_back
typedef pair<int,int> pii;
const double PI= acos(-1.0);
const int M = 2e5+7;
const int mod = 1e9+7;
struct node{
int l,r,id,ans;
}p[M];
bool cmp(node a,node b){
return a.r<b.r;
}
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans;
}
int m;
int prime[M];//第幾個質數的值
int v[M];//i的最小質數
vector<int>pv[M];//數i的質因子
void gao(int n)//預處理1-n每個數的質因子,方便加速後續處理
{
for(int i=2;i<=n;i++)
{
if(v[i]==0)prime[++m]=i,v[i]=i;
for(int j=1;j<=m&&i*prime[j]<=n;j++)
{
v[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
for(int i=1;i<=m;i++)
for(int j=prime[i];j<=n;j+=prime[i])
pv[j].pb(prime[i]);
}
stack<int>s[M];//質數x ,線上段樹中出現的位置id
int a[M],ans[M];
int rt[M];
//n*logn *logn = 1e5*17*17 2e5 * 200 足夠了!
int tr[M*130];//區間乘積
int ls[M*130],rs[M*130],cnt;
void bd(int &o,int l,int r){
if(!o)o=++cnt;
tr[o]=1;
if(l==r)return ;
int m=(l+r)/2;
bd(ls[o],l,m);
bd(rs[o],m+1,r);
}
//up()
void up(int pre,int &o,int l,int r,int x,int d){//可持久化線段樹
o=++cnt;
tr[o]=tr[pre];
ls[o]=ls[pre];
rs[o]=rs[pre];
tr[o]=(ll)tr[o]*d%mod;
if(l==r)return ;
int m=(l+r)/2;
if(x<=m)up(ls[pre],ls[o],l,m,x,d);
else up(rs[pre],rs[o],m+1,r,x,d);
}
ll qu(int o,int l,int r,int x,int y){
if(x<=l&&r<=y){
return tr[o];
}
int m=(l+r)/2;
ll ans=1;
if(x<=m)ans=ans*qu(ls[o],l,m,x,y)%mod;
if(y>m)ans=ans*qu(rs[o],m+1,r,x,y)%mod;
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
gao(200000);
int n,q;
cin>>n;
bd(rt[0],1,n);//先初始化第一顆樹,方便後面的樹繼承
for(int i=1;i<=n;i++)cin>>a[i];
cin>>m;
for(int i=1;i<=m;i++)
cin>>p[i].l>>p[i].r;
int sz=1;
for(int i=1;i<=n;i++)//列舉右端點
{
rt[i]=rt[i-1];//由於要在當前樹上多次更新,我們先把上棵樹的根繼承過來,然後在這個基礎上更新
int tp=a[i],tm=0,tnm=0;
for(auto x:pv[a[i]]){
tm=0,tnm=0;
while(tp%x==0)tp/=x,tm++;
tnm=tm;
up(rt[i],rt[i],1,n,i,qpow(x,tm));
while(!s[x].empty()&&tm){
up(rt[i],rt[i],1,n,s[x].top(),qpow(x,mod-2));
s[x].pop();tm--;
}
for(int j=1;j<=tnm;j++)s[x].push(i);
}
//qu(1,1,n,j,i) --> (j,i) 中所有數的LCM
}
int lst=0;
for(int i=1;i<=m;i++){
int l,r;
l=(p[i].l+lst)%n+1,r=(p[i].r+lst)%n+1;
if(l>r)swap(l,r);
// cout<<rt[r]<<" - "<<endl;
lst=qu(rt[r],1,n,l,r);
cout<<lst<<endl;
}
return 0;
}
/*
10
10 2 8 8 8 8 8 10 2 3
10
1 2
6 1
4 10
1 9
9 1
6 10
3 3
8 1
4 10
6 7
*/
相關文章
- 區間k小值(可持久化線段樹)持久化
- 可持久化線段樹持久化
- Codeforces Round #373 (Div. 1) C. Sasha and Array 線段樹
- 線段樹 區間乘法加法混合
- 線段樹維護區間等差數列
- CodeForces 145 E. Lucky Queries(線段樹)
- P3834 【模板】可持久化線段樹 2持久化
- Codeforces Round 970 (Div. 3)A~F
- HDU 4027 Can you answer these queries? (線段樹 區間開方)
- 「學習筆記」可持久化線段樹筆記持久化
- Codeforces Round #541 (Div. 2)
- Codeforces Round 940 (Div. 2)
- Codeforces Round 934 (Div. 2)
- Codeforces Round 932 (Div. 2)
- Codeforces Round 948 (Div. 2)
- Codeforces Round #639 (Div. 2)
- Codeforces Round #672 (Div. 2)
- Codeforces Round #682 (Div. 2)
- Codeforces Round #678 (Div. 2)
- Codeforces Round #673 (Div. 2)
- Codeforces Round 987 (Div. 2)
- Codeforces Round 976 (Div. 2)
- Codeforces Round 975 (Div. 2)
- Codeforces Round 986 (Div. 2)
- Codeforces Round 973 (Div. 2)
- Codeforces Round 969 (Div. 2)
- Codeforces Round 873 (Div. 2)
- Codeforces Round 967 (Div. 2)
- Codeforces Round 965 (Div. 2)
- Codeforces Round 963 (Div. 2)
- Codeforces Round 979 (Div. 2)
- Codeforces Round 972 (Div. 2)
- Codeforces Round 949 (Div. 2)
- Codeforces Round 955 (Div. 2)
- Codeforces Round 951 (Div. 2)
- Codeforces Round 961 (Div. 2)
- Codeforces Round 958 (Div. 2)
- Codeforces Round 960 (Div. 2)