您的位置:首页 > 其它

Educational Codeforces Round 22 E. Army Creation 主席树 或 分块

2017-06-09 12:43 393 查看
http://codeforces.com/contest/813/problem/E

题目大意:

给出长度为n的数组和k, 大小是1e5级别。

要求在线询问区间[l, r]权值, 权值定义为对于所有不同元素x在区间出现的次数和, 如果x出现次数>k, 那么按k算。

重要转换: 考虑一个区间[L, R]的某个数A[i], 它对答案有贡献 当且仅当 它前面与他权值相同的数中第k个数的位置(记为B[i]) < L

预处理B[], 每次询问就转化为 区间[L, R]中有多少个B[i] < L

可以用主席树 或者 分块解决。

也可以用此题的方法求区间不同元素个数, 其实就是k = 1的情况。

主席树代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
using namespace std;

typedef long long ll;

#define N 100050
const int INF = 1 << 30;
const double pi = acos(-1);

int pt;
int a
, b
, id
, dp[350]
;
int bl[350], br[350];
vector<int> lis
;

int main()
{
//freopen("in.in", "r", stdin);
//freopen("out.out", "w", stdout);

int n, k, Q, lastans = 0, l, r;
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), lis[a[i]].push_back(i);

for (int i = 1; i <= 100000; ++i)
{
if (lis[i].size() <= k) continue;
for (int j = k; j < lis[i].size(); ++j) b[lis[i][j]] = lis[i][j - k];
}

int block = (int)sqrt(n + 1);

for (int i = 1; ; ++i)
{
l = (i - 1) * block + 1;
r = min(n, l + block - 1);
bl[i] = l, br[i] = r;
for (int j = l; j <= r; ++j) dp[i][b[j]]++, id[j] = i;
for (int j = 1; j <= 100000; ++j) dp[i][j] += dp[i][j - 1];
if (r == n) break;
}

scanf("%d", &Q);
while (Q--)
{
scanf("%d %d", &l, &r);
l = (l + lastans) % n + 1;
r = (r + lastans) % n + 1;
if (l > r) swap(l, r);

int res = 0;
if (id[l] == id[r])
{
for (int i = l; i <= r; ++i)
res += b[i] < l;
}
else
{
for (int i = l; i <= br[id[l]]; ++i) res += b[i] < l;
for (int i = bl[id[r]]; i <= r; ++i) res += b[i] < l;
for (int i = id[l] + 1; i <= id[r] - 1; ++i) res += dp[i][l - 1];
}
printf("%d\n", res);
lastans = res;
}

return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: