不错的分块题。。。附上BC的官方题解。。。
令 f(l,r) 表示 [l,r] 的答案。 我们对于序列分块,对于第 i 块,令 Si 为第 i 块的左端点。 令 g(a,b) 表示第 a 块开头到第 b 块末尾这一段序列的答案。下面我们讨论如何求 g(a,b) 。 我们枚举 a ,再枚举 j(Sa≤j≤n) ,考虑 j 转移到 j+1 , f(Sa,j) 和 f(Sa,j+1) 的关系。f(Sa,j+1)=f(Sa,j)−Asum(Aj+1)j+1+Asum(Aj+1)+1j+1其中 sum(x) 表示 x 在区间 [Sa,j] 中出现的次数,这样我们就能用 nn−√logn 的时间求出 g(a,b) 。 令 h(i,j) 表示 i 在前 j 个块中出现的次数,这个也很容易用 n−√ 的时间求出。 考虑询问 [l,r] ,两端的我们可以暴力求出来,中间的块内答案可以直接用 g 数组求出。然后我们可以用类似求 g 数组的方法将两端的数加入中间的块内。复杂度 O(Qn−√logn) 。 考虑到那个 log 为快速幂的复杂度,又因为每一个 ab 我们都可以发现 a 一定是序列中的数, b 一定小于 a 在序列中出现的次数,所以我们可以 O(n) 预处理,用 vector 存起来即可。 总复杂度 O(nn−√+Qn−√) 。
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <time.h>
#define maxn 50005
#define maxm 305
#define eps 1e-7
#define mod 1000000007
#define INF 0x3f3f3f3f
#define PI (acos(-1.0))
#define lowbit(x) (x&(-x))
#define mp make_pair
#define ls o<<1
#define rs o<<1 | 1
#define lson o<<1, L, mid
#define rson o<<1 | 1, mid+1, R
#define pii pair<int, int>
#pragma comment(linker, "/STACK:16777216")
typedef long long LL;
typedef unsigned long long ULL;
//typedef int LL;
using namespace std;
LL qpow(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base;base=base*base;b/=2;}return res;}
LL powmod(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base%mod;base=base*base%mod;b/=2;}return res;}
// head
vector<LL> vec[maxn];
LL res[maxm][maxm];
int C[maxm][maxn];
LL a[maxn];
LL b[maxn];
int aa[maxn];
int x[maxn];
int c[maxn];
int n, m;
void work()
{
memset(C, 0, sizeof C);
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) scanf("%lld", &a[i]), b[i] = a[i];
sort(b, b+n);
int cnt = unique(b, b+n) - b;
for(int i = 0; i < n; i++) x[i] = lower_bound(b, b+cnt, a[i]) - b;
for(int i = 0; i < cnt; i++) vec[i].clear();
for(int i = 0; i < cnt; i++) vec[i].push_back(0);
for(int i = 0; i < n; i++) {
LL t = vec[x[i]][vec[x[i]].size() - 1];
if(vec[x[i]].size() == 1) t = 1;
t = t * a[i] % mod;
vec[x[i]].push_back(t);
}
int s = sqrt(n), sn = n / s;
if(n % s) sn++;
LL ans = 0;
for(int i = 0; i < sn; i++) {
ans = 0;
memset(c, 0, sizeof c);
for(int j = i * s; j < n; j++) {
int loc = j / s;
ans = (ans - vec[x[j]][c[x[j]]] + vec[x[j]][c[x[j]] + 1] + mod) % mod;
c[x[j]]++;
res[i][loc] = ans;
}
}
for(int i = 0; i < sn; i++)
for(int j = 0; j < (i + 1) * s && j < n; j++)
C[i][x[j]]++;
ans = 0;
memset(c, 0, sizeof c);
while(m--) {
LL l, r, ll, rr;
scanf("%lld%lld", &ll, &rr);
l = min((ll ^ ans) % n, (rr ^ ans) % n);
r = max((ll ^ ans) % n, (rr ^ ans) % n);
ans = 0;
int loc1 = l / s + 1;
int loc2 = r / s - 1;
if(loc2 >= loc1) ans = res[loc1][loc2];
int tcnt = 0;
if(l / s != r / s) {
for(int i = l; i < loc1 * s; i++) aa[tcnt++] = x[i];
for(int i = (loc2 + 1) * s; i <= r; i++) aa[tcnt++] = x[i];
}
else {
for(int i = l; i <= r; i++) aa[tcnt++] = x[i];
}
for(int i = 0; i < tcnt; i++) {
if(c[aa[i]] == 0 && loc2 >= loc1) c[aa[i]] += C[loc2][aa[i]] - (loc1 ? C[loc1-1][aa[i]] : 0);
ans = (ans - vec[aa[i]][c[aa[i]]] + vec[aa[i]][c[aa[i]] + 1] + mod) % mod;
c[aa[i]]++;
}
for(int i = 0; i < tcnt; i++) c[aa[i]] = 0;
printf("%lld\n", ans);
}
}
int main()
{
int _;
scanf("%d", &_);
while(_--) work();
return 0;
}