Codeforces Round #675 (Div. 2) 1442 F - Boring Queries 可持久化線段樹維護 區間乘法

夕林山寸發表於2020-10-06

 

#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
*/

 

相關文章