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++11 (judge verdict: Wrong Answer)

#include <vector>
#include <iostream>

using namespace std;

long long gcd(long long a, long long b)
{
	if (a == 0) { return b; }
	if (b == 0) { return a; }

	if (a > b) { return gcd(b, a % b); }

	return gcd(a, b % a);
}

long long lcm(long long a, long long b)
{
	return a / gcd(a, b) * b;
}

vector<int> G; // i --> G[i] Graph

vector<bool> visited;

vector<vector<int> > cycles;

void rec(int p)
{
	visited[p] = true;

	cycles.back().push_back(p);

	if (!visited[G[p]])
	{
		rec(G[p]);
	}
}

int main()
{
	int V, Q;

	scanf("%d", &V);
	scanf("%d", &Q);

	G = vector<int>(V);

	for (int i = 0; i < V; i++)
	{
		scanf("%d", &G[i]); G[i]--; // 1 -> 0 indexed
	}

	visited = vector<bool>(V, false);

	for (int i = 0; i < V; i++)
	{
		if (!visited[i])
		{
			cycles.push_back(vector<int>());

			rec(i);
		}
	}

	vector<int> val(V, 0), num(V, 0);

	for (int i = 0; i < cycles.size(); i++)
	{
		int sum = 0;

		for (int j = 0; j < cycles[i].size(); j++)
		{
			sum += cycles[i][j] + 1;
		}

		for (int j = 0; j < cycles[i].size(); j++)
		{
			val[cycles[i][j]] = sum;

			num[cycles[i][j]] = cycles[i].size();
		}
	}

	vector<vector<int> > sum(V, vector<int>(41));

	for (int i = 0; i < V; i++)
	{
		sum[i][num[i]] += 1;

		if (i == 0) { continue; }

		for (int j = 1; j <= 40; j++)
		{
			sum[i][j] += sum[i - 1][j];
		}
	}

	int l, r;

	for (int i = 0; i < Q; i++)
	{
		scanf("%d", &l); l--; // 1 -> 0 indexed
		scanf("%d", &r); r--;

		long long rep = 1; int c;

		for (int i = 2; i <= 40; i++)
		{
			c = sum[r][i];

			if (l != 0)
			{
				c -= sum[l - 1][i];
			}

			if (c != 0)
			{
				rep = lcm(rep, i);
			}
		}

		int ret = 0;

		for (int j = l; j <= r; j++)
		{
			ret = (ret + rep / num[j] * val[j]) % 1000000007;
		}

		printf("%d\n", ret);
	}

	return 0;
}