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 <bits/stdc++.h>
using namespace std;

int p[100010];
int done[100010];
vector<int> v;
int len = 0;
int dfs(int x){
	if( done[x]++ ) return 0;
	v.push_back(x);
	len++;
	dfs(p[x]);
}


#define lcm(a,b) (a/__gcd(a,b)*b)
template<class T>
struct SegmentTree{
	int n_;
	vector<T> seg;
	// [1,N]
	SegmentTree(int N){
		n_ = 1;
		while(n_ < N ) n_ *= 2;
		seg.resize(2*n_,1); //????¨????
	}
	void add(int i,int v){
		i += n_-1;
		seg[i] = v;
		i /= 2;
		while(i){
			seg[i] = lcm(seg[i*2],seg[i*2+1]); //????¨????
			i /= 2;
		}
	}
	T get(int l,int r,int k,int a,int b){
		if( b < l || r < a ) return 1; //????¨????
		if( l <= a && b <= r ){
			return seg[k];
		}
		int m = (a+b)/2;
		return lcm(get(l,r,k*2,a,m),get(l,r,k*2+1,m+1,b)); //????¨????
	}
	inline T get(int l,int r){
		return get(l,r,1,1,n_);
	}
};

struct BIT{
	vector<int> seg;
	// [1,n]
	BIT(int N){
		seg.resize(N+1,0);
	};
	int get(int i){
		return seg[i];
	}
	void add(int i,int x){
		seg[i] = seg[i]+x;
	}
	void init(){
		for(int i = 1 ; i < seg.size() ; i++){
			seg[i] += seg[i-1];
			seg[i] %= 1000000007;
		}
	}
	int get(int l,int r){
		return (get(r) - get(l-1))%1000000007;
	}
};



int main(){
	int N,Q;
	cin >> N >> Q;
	for(int i = 1 ; i <= N ; i++){
		scanf("%d",&p[i]);
	}
	
	SegmentTree<long long> LCM(N);
	vector<BIT> bit1(41,BIT(N));

	for(int i = 1; i <= N ; i++){
		if( done[i] ) continue;
		len = 0;
		v.clear();
		dfs(i);
		long long sum = 0;
		for(int j = 0 ; j < v.size() ; j++){
			sum += v[j];
			sum %= 1000000007;
			LCM.add(v[j],len);
		}
		for(int j = 0 ; j < v.size() ; j++){
			bit1[len].add(v[j],sum);
		}
	}
	for(int j = 1 ; j <= 40 ; j++){
		bit1[j].init();
	}
	for(int i = 0 ; i < Q ; i++){
		long long ans = 0;
		long long l,r;
		cin >> l >> r;
		long long len = LCM.get(l,r);
		for(int j = 1 ; j <= 40 ; j++){
			//if( len % j != 0 ) continue;
			ans += (len/j) % 1000000007 * bit1[j].get(l,r) % 1000000007;
			ans %= 1000000007;
		}
		printf("%d\n",(int)ans);
	}
	
}