Problem:
問題 G : Perm Query

問題文

\{1,  2,  … ,  N\}の順列 (p(1),  p(2),  … ,  p(n)) が与えられる．
(l_i,  r_i) からなるクエリが Q 個与えられるので，各クエリに対して以下の擬似コードによる処理結果を出力せよ．

ret   :=   0, (x(1),  x(2),  … ,  x(N))  :=  (1,  2,  … ,  N) とおく．

各i   ∈ \{1,   2,  … ,   N\} について y(i) := p(x(i)) とする．

各i   ∈ \{1,   2,  … ,   N\} について x(i)   =  y(i)とする．

ret   :=  ret + x(l_i) + x(l_i+1) + …  + x(r_i)

もし (x(l_i),  x(l_i+1),  … ,  x(r_i)) = (l_i,  l_i+1,  … ,  r_i) なら (ret   mod10^9+7) を出力して終了する．そうでないなら 2 行目に戻る．

入力形式

入力は以下の形式で与えられる

N Q
p(1) p(2) ... p(N)
l_0 r_0
...
l_{Q-1} r_{Q-1}

出力形式

各クエリに対する出力を1行ずつ出力せよ．

制約

1 ≤ N ≤ 10^5

1 ≤ Q ≤ 10^4

(p_1,  p_2,  … ,  p_N) は (1,  2,  … ,  N) の順列になっている．

各 i に対して，ある 1 ≤ k ≤ 40 が存在して，p^k(i)=i となる．ここで，p^k(i) は p(p(p(… p(i)… ))) で p が k 回現れるもの．

1 ≤ l_i   ≤   r_i   ≤ N

入出力例

入力例 1

5 2
5 1 2 3 4
1 1
2 4

出力例 1

15
45

擬似コード中の順列(x(1),   x(2),   … ,  x(N))は以下のように変化する．

1 2 3 4 5
5 1 2 3 4
4 5 1 2 3
3 4 5 1 2
2 3 4 5 1
1 2 3 4 5

入力例 2

10 5
3 1 2 5 4 10 6 7 9 8
1 10
1 5
3 3
5 10
9 10

出力例 2

660
90
6
178
67

Solution in C++ (judge verdict: Time Limit Exceeded)

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>	
#include<map>
#include<set>
#include<utility>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<cstdio>
#include<sstream>
#include<iomanip>
#include<assert.h>
#include<typeinfo>
#define loop(i,a,b) for(int i=a;i<b;i++) 
#define rep(i,a) loop(i,0,a)
#define pb push_back
#define all(in) in.begin(),in.end()
#define shosu(x) fixed<<setprecision(x)
using namespace std;
//kaewasuretyuui
typedef long long ll;
//#define int ll
typedef ll Def;
typedef pair<Def,Def> pii;
typedef vector<Def> vi;
typedef vector<vi> vvi;
typedef vector<pii> vp;
typedef vector<vp> vvp;
typedef vector<string> vs;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef pair<Def,pii> pip;
typedef vector<pip>vip;
//#define mt make_tuple
//typedef tuple<pii,int,int> tp;
//typedef vector<tp> vt;
template<typename A,typename B>bool cmin(A &a,const B &b){return a>b?(a=b,true):false;}
template<typename A,typename B>bool cmax(A &a,const B &b){return a<b?(a=b,true):false;}
//template<class C>constexpr int size(const C &c){return (int)c.size();}
//template<class T,size_t N> constexpr int size(const T (&xs)[N])noexcept{return (int)N;}
const double PI=acos(-1);
const double EPS=1e-7;
Def inf = sizeof(Def) == sizeof(long long) ? 2e18 : 1e9;
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
typedef ll SegT;
const SegT defvalue=0;
class SegTree{
	private:
		vector<SegT>val;
		int n;
		SegT combine(SegT a,SegT b){return max(a,b);}
	public:
		SegTree(int size){
			n=1;
			while(n<size)n<<=1;
			val=vector<SegT>(2*n,defvalue);
		}
		SegTree(const vector<SegT> &in){
			n=1;
			while(n<in.size())n<<=1;
			val=vector<SegT>(2*n,defvalue);
			for(int i=n-1+in.size()-1;i>=0;i--){
				if(n-1<=i)val[i]=in[i-(n-1)];
				else val[i]=combine(val[i*2+1],val[i*2+2]);
			}
		}
		void update(int i,SegT a){
			i+=n-1;
			val[i]=a;
			while(i>0){
				i=(i-1)/2;
				val[i]=combine(val[i*2+1],val[i*2+2]);
			}
		}
		SegT query(int a,int b,int k=0,int l=0,int r=-1){//[a,b)
			if(r==-1)r=n;
			if(r<=a||b<=l)return defvalue;
			if(a<=l&&r<=b)return val[k];
			else return combine(query(a,b,k*2+1,l,(l+r)/2),query(a,b,k*2+2,(l+r)/2,r));
		}
		void tmp(){
			rep(i,val.size())cout<<" "<<val[i];cout<<endl;
		}
};
//nCr mod m
#define MOD 1000000007
#define M 1000000
vector<ll> fact;
bool h=false;
void init(){
	h=true;
	fact=vector<ll>(M);
	fact[0]=fact[1]=1;
	loop(i,2,M)fact[i]=fact[i-1]*i%MOD;
}
// a^b mod MOD
ll powmod(ll a,ll b,ll m){
	ll out=1;
	ll p=a%m;
	while(b){
		if(b&1)out=out*p%m;
		p=p*p%m;
		b>>=1;
	}
	return out;
}
int main(){
	ll n,q;
	cin>>n>>q;
	vi in(n);
	rep(i,n)cin>>in[i];
	vp sum(n);
	rep(i,n){
		ll t=i;
		int co=0;
		do{
			co++;
			sum[i].first+=t+1;
			sum[i].first%=MOD;
			t=in[t]-1;
		}while(t!=i);
		sum[i].second=co;
	}
//	rep(i,n)cout<<sum[i].first<<" "<<sum[i].second<<endl;
	vector<SegTree>dp(40,SegTree(n));
	rep(i,n){
		ll t=sum[i].second;
		loop(j,2,40){
			int co=0;
			while(t%j==0){
				co++;
				t/=j;
			}
			dp[j].update(i,co);
		}
	}
	while(q--){
		ll l,r;cin>>l>>r;
		l--;
		ll t=1;
		rep(i,40){
			ll co=dp[i].query(l,r);
//			cout<<i<<" "<<co<<endl;
			if(co!=inf)rep(j,co)t*=i;
		}
		ll out=0;
		loop(i,l,r)(out+=t*powmod(sum[i].second,MOD-2,MOD)*sum[i].first)%=MOD;
		cout<<out<<endl;
	}
}