小B的询问
题目描述
小B 有一个长为 n n n 的整数序列 a a a,值域为 [ 1 , k ] [1,k] [1,k]。
他一共有 m m m 个询问,每个询问给定一个区间 [ l , r ] [l,r] [l,r],求:
∑ i = 1 k c i 2 \sum\limits_{i=1}^k c_i^2 i=1∑kci2
其中 c i c_i ci 表示数字 i i i 在 [ l , r ] [l,r] [l,r] 中的出现次数。
小B请你帮助他回答询问。
输入格式
第一行三个整数 n , m , k n,m,k n,m,k。
第二行 n n n 个整数,表示 小B 的序列。
接下来的 m m m 行,每行两个整数 l , r l,r l,r。
输出格式
输出 m m m 行,每行一个整数,对应一个询问的答案。
样例 #1
样例输入 #1
6 4 3
1 3 2 1 1 3
1 4
2 6
3 5
5 6
样例输出 #1
6
9
5
2
提示
【数据范围】
对于 100 % 100\% 100% 的数据, 1 ≤ n , m , k ≤ 5 × 1 0 4 1\le n,m,k \le 5\times 10^4 1≤n,m,k≤5×104。
代码:
cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int>PII;
const int N = 1e6 + 10;
const int MOD = 998244353;
const int INF = 0X3F3F3F3F;
const int dx[] = {-1, 1, 0, 0, -1, -1, +1, +1};
const int dy[] = {0, 0, -1, 1, -1, +1, -1, +1};
const int M = 1e9 + 7;
//莫队算法板子(优雅的暴力)
ll res;
ll pos[N];
ll a[N];
ll cnt[N];//记录出现的次数
ll ans[N];//记录答案
struct que
{
int l, r, k;
bool operator < (const que&w) const
{
return pos[l] == pos[w.l] ? r < w.r : l < w.l;
};
}q[N];
void add(int x)
{
cnt[a[x]] ++;
res += (cnt[a[x]]) * (cnt[a[x]]) - (cnt[a[x]] - 1) * (cnt[a[x]] - 1);
}
void sub(int x)
{
cnt[a[x]] --;
res -= (cnt[a[x]] + 1) * (cnt[a[x]] + 1) - (cnt[a[x]]) * (cnt[a[x]]);
}
int main()
{
int n, m, k;
cin >> n >> m >> k;
int siz = sqrt(n);
for(int i = 1; i <= n; i ++)
{
cin >> a[i];
pos[i] = i / siz;
}
for(int i = 1; i <= m; i ++)
{
cin >> q[i].l >> q[i].r;
q[i].k = i;
}
sort(q + 1, q + 1 + m);
int l = 1, r = 0;
for(int i = 1; i <= m; i ++)
{
while(q[i].l < l) add(-- l);
while(q[i].r > r) add(++ r);
while(q[i].l > l) sub(l ++);
while(q[i].r < r) sub(r --);
ans[q[i].k] = res;
}
for(int i = 1; i <= m; i ++) cout << ans[i] << endl;
return 0;
}
莫队(发现了nmd,map得时间复杂度都是log,莫队又是暴力直接就超时了呜呜呜)
Little Elephant and Array
题面翻译
小象喜欢和数组玩。现在有一个数组 a a a,含有 n n n 个正整数,记第 i i i 个数为 a i a_i ai。
现在有 m m m 个询问,每个询问包含两个正整数 l j l_j lj 和 r j ( 1 ⩽ l j ⩽ r j ⩽ n ) r_j \;(1\leqslant l_j\leqslant r_j\leqslant n) rj(1⩽lj⩽rj⩽n),小象想知道在 A l j A_{l_j} Alj 到 A r j A_{r_j} Arj 之中有多少个数 x x x,其出现次数也为 x x x。
输入格式
第一行 n n n 和 m m m, n n n 表示数组大小, m m m 表示询问个数;
第二行共 n n n 个数,第 i i i 个数为 a i a_i ai 的值;
接下来 m m m 行,每行两个数 l j l_j lj 和 r j r_j rj,意义如题面。
输出格式
共 m m m 行,每行一个数,表示每一次询问的答案。
样例输入 #1
7 2
3 1 2 2 3 3 7
1 7
3 4
样例输出 #1
3
1
代码:
cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int>PII;
const int N = 1e6 + 10;
const int MOD = 998244353;
const int INF = 0X3F3F3F3F;
const int dx[] = {-1, 1, 0, 0, -1, -1, +1, +1};
const int dy[] = {0, 0, -1, 1, -1, +1, -1, +1};
const int M = 1e9 + 7;
//莫队算法板子(优雅的暴力)
//nmd map得时间复杂度
ll res;
ll pos[N];
ll a[N];
ll cnt[N];//记录出现的次数
ll ans[N];//记录答案
ll n, m;
struct que
{
ll l, r, k;
}q[N];
bool cmp(que a, que b)
{
return pos[a.l] == pos[b.l] ? a.r < b.r : pos[a.l] < pos[b.l];
}
void add(ll x)
{
if(a[x] > n) return ;
if(cnt[a[x]] == a[x]) res --;
cnt[a[x]] ++;
if(cnt[a[x]] == a[x]) res ++;
}
void sub(ll x)
{
if(a[x] > n) return ;
if(cnt[a[x]] == a[x]) res --;
cnt[a[x]] --;
if(cnt[a[x]] == a[x]) res ++;
}
int main()
{
cin >> n >> m;
ll siz = sqrt(n);
for(ll i = 1; i <= n; i ++)
{
scanf("%lld", &a[i]);
pos[i] = i / siz;
}
for(ll i = 1; i <= m; i ++)
{
scanf("%lld%lld", &q[i].l, &q[i].r);
q[i].k = i;
}
sort(q + 1, q + 1 + m, cmp);
ll l = 1, r = 0;
for(ll i = 1; i <= m; i ++)
{
while(q[i].l < l) add(-- l);
while(q[i].r > r) add(++ r);
while(q[i].l > l) sub(l ++);
while(q[i].r < r) sub(r --);
ans[q[i].k] = res;
}
for(ll i = 1; i <= m; i ++) cout << ans[i] << '\n';
return 0;
}