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 <utility>
using namespace std;
const int MAX_N = 1 << 17, mod = 1000000007;
int gcd(int a, int b){
  if(b > a) swap(a,b);
  if(b == 0) return a;
  return gcd(b,a%b);
}

int lcm(int a, int b){
  int d = gcd(a,b);
  return a/d*b;
}

int n;
int dat[2*MAX_N-1][2];

void init(int n_){
  n = 1;
  while(n < n_) n *= 2;
  for(int i = 0; i < 2*n-1; ++i){
    dat[i][0] = 1;
    dat[i][1] = 0;
  }
}

void update(int N){
  for(int i = 0; i < N; ++i){
    int k = i + n - 1;
    while(k > 0){
      k = (k-1)/2;
      int m = lcm(dat[k*2+1][0],dat[k*2+2][0]);
      dat[k][0] = m;
      dat[k][1] = (m/dat[k*2+1][0]*dat[k*2+1][1]%mod + m/dat[k*2+2][0]*dat[k*2+2][1]%mod)%mod;
    }
  }
}

//[a, b)テ」ツ?ョlcmテ」ツ?ィretテ」ツ?ョテ・ツ?、テ」ツつ津ヲツアツづ」ツつ?」ツつ凝」ツ??
pair<int,int> query(int a, int b, int k, int l, int r){
  if(r <= a || b <= l) return make_pair(1,0);
  if(a <= l && r <= b) return make_pair(dat[k][0],dat[k][1]);
  else{
    pair<int,int> vl = query(a,b,k*2+1,l,(l+r)/2);
    pair<int,int> vr = query(a,b,k*2+2,(l+r)/2,r);
    int m = lcm(vl.first,vr.first);
    int c = (m/vl.first*vl.second%mod + m/vr.first*vr.second%mod)%mod;
    return make_pair(m,c);
  }
}

int main(){
  int N, Q;
  cin >> N >> Q;
  int P[N];
  for(int i = 0; i < N; ++i){
    cin >> P[i];
    --P[i];
  }
  init(N);
  for(int i = 0; i < N; ++i){
    int cur = P[i], t = 1, c = i+1;
    while(cur != i){//テ・ツ按カテァツエツ?」ツ?凝」ツつ嘉」ツ??0テ・ツ崢榲、ツサツ・テ、ツクツ凝」ツ?ァテヲツュツ「テ」ツ?セテ」ツつ?
      c += cur + 1;
      cur = P[cur];
      ++t;
    }
    //update(i,t,c);
    dat[i+n-1][0] = t;
    dat[i+n-1][1] = c;
  }
  update(N);
  int l, r;
  for(int i = 0; i < Q; ++i){
    cin >> l >> r;
    --l;
    cout << query(l,r,0,0,n).second << endl;
  }
  return 0;
}