与えられた置換pを巡回置換の合成σ1σ2...σkに分解して、ある巡回置換σに注目する。σの長さがdとすると、
- 列σxの区間[l,r]の総和
- 列σ2xの区間[l,r]の総和
- ...
- 列σdx=xの区間[l,r]の総和
をすべて足せばこの巡回置換を一周した場合の総和が求まることになる。この際、巡回置換に現れるすべての数は同じ回数だけ[l,r]に現れるので、上の総和は巡回置換に登場する数の総和の倍数になっている。
また、問題のようにすべての巡回置換を同時に適用した場合、次にもとに戻るのは(区間[l,r]に登場する)すべての巡回置換の長さの最小公倍数である。これをLCM(l,r)とすると、LCM(l,r)回の操作を行う場合、長さdの巡回置換についてはLCM(l,r)/d周することになる。この際、巡回置換に登場する数で最初に区間[l,r]に含まれていたものがq個であるとすると、巡回置換に登場する数はそれぞれqLCM(l,r)/d回足されることになる。
実装で迷った末に、Moのアルゴリズムを使った。
区間[l,r]についての値がわかっているとき、[l,r+1]の値を考える。まず、区間が伸びたことによって操作回数がLCM(l,r)からLCM(l,r+1)に伸びるので、既存の値がLCM(l,r+1)/LCM(l,r)倍になる。また、位置r+1が追加されるので、この位置を含む巡回置換σの長さdについて、(巡回置換σに登場する数の総和)×LCM(l,r+1)/dが加算されることになり、新しい値が求まる。区間が縮む場合も同様に書ける。
LCM(l,r)の値を得るのにsparse tableが使えるから計算量の問題はないと思って書き出したのだが、伸縮の際にmodの割り算が必要になるので結局logがついてO(NQlogN)だった。
lcmと同時に、それぞれの巡回置換の総和もセグメント木で持てばよいらしい。それはそうか……