题目链接:BZOJ - 2821

题目分析

因为强制在线了,所以无法用莫队..可以使用分块来做。

做法是,将 n 个数分成 n/x 个块,每个块大小为 x 。先预处理出 f[i][j] ,表示从第 i 个块到第 j 个块的出现次数为偶数的数的个数。

这个复杂度是 n * (n / x) 的。

然后把数与位置存在结构体里,按照数字第一关键字,位置为第二关键字排序。这样是为了方便之后二分查找 [l, r] 中 Num 出现了几次。

对于每次询问,先把答案加上中间包含的整块的答案。然后对于两边至多 2x 个数,单独处理,二分求出它们在中间整块中出现的次数,以更新答案。

更新的思路大概是:看加上当前这个数后,这个数出现的次数是从odd -> even 还是从 even -> odd ,还是 0 -> 1,然后选择 ++Ans 或是 --Ans 或是什么也不做。

处理询问的复杂度是 n * x * logn 。

分析 x 的最优大小。总复杂度为 (n^2 / x) + (nlogn * x) ,由均值不等式得,当 n^2 / x == nlogn * x 时,总复杂度最小,所以 x 的最优值为 x = sqrt(n / logn) 。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm> using namespace std; const int MaxN = 100000 + 5, MaxBlk = 1300 + 5; inline void Read(int &num) {
char c = getchar();
while (c < '0' || c > '9') c = getchar();
num = c - '0'; c = getchar();
while (c >= '0' && c <= '9') {
num = num * 10 + c - '0';
c = getchar();
}
} int n, m, Cset, Ans, BlkSize, LastBlk;
int A[MaxN], First[MaxN], Last[MaxN], Cnt[MaxN], f[MaxBlk][MaxBlk], L[MaxBlk], R[MaxBlk]; struct ES
{
int Pos, Num;
bool operator < (const ES &b) const {
if (Num == b.Num) return Pos < b.Pos;
return Num < b.Num;
}
} E[MaxN]; int Get(int s, int t, int Num) {
if (s > t || s > E[Last[Num]].Pos || t < E[First[Num]].Pos) return 0;
int l, r, mid, pl, pr;
l = First[Num]; r = Last[Num];
while (l <= r) {
mid = (l + r) >> 1;
if (E[mid].Pos >= s) {
pl = mid;
r = mid - 1;
}
else l = mid + 1;
}
l = First[Num]; r = Last[Num];
while (l <= r) {
mid = (l + r) >> 1;
if (E[mid].Pos <= t) {
pr = mid;
l = mid + 1;
}
else r = mid - 1;
}
return pr - pl + 1;
} int main()
{
//Init
Read(n); Read(Cset); Read(m);
for (int i = 1; i <= n; ++i) Read(A[i]);
BlkSize = (int)sqrt((double)n / log((double)n) * log(2.0));
LastBlk = (n - 1) / BlkSize + 1;
for (int i = 1; i <= LastBlk; ++i) {
L[i] = (i - 1) * BlkSize + 1;
R[i] = i * BlkSize;
}
R[LastBlk] = n;
memset(Cnt, 0, sizeof(Cnt));
for (int i = 1; i <= LastBlk; ++i) {
for (int j = 1; j <= Cset; ++j) Cnt[j] = 0;
for (int j = i; j <= LastBlk; ++j) {
f[i][j] = f[i][j - 1];
for (int k = L[j]; k <= R[j]; ++k) {
++Cnt[A[k]];
if ((Cnt[A[k]] & 1) == 0) ++f[i][j];
else if (Cnt[A[k]] != 1) --f[i][j];
}
}
}
for (int i = 1; i <= n; ++i) {
E[i].Pos = i; E[i].Num = A[i];
}
sort(E + 1, E + n + 1);
for (int i = 1; i <= n; ++i) {
if (First[E[i].Num] == 0) First[E[i].Num] = i;
Last[E[i].Num] = i;
}
//The array Cnt[] will be used later.
memset(Cnt, 0, sizeof(Cnt)); //Solve queries
int l, r, x, y, Lx, Ry, G;
Ans = 0;
for (int Case = 1; Case <= m; ++Case) {
Read(l); Read(r);
l = (l + Ans) % n + 1; r = (r + Ans) % n + 1;
if (l > r) swap(l, r);
x = (l - 1) / BlkSize + 1;
if (l != L[x]) ++x;
y = (r - 1) / BlkSize + 1;
if (r != R[y]) --y;
if (x > y) {
Ans = 0;
for (int i = l; i <= r; ++i) {
++Cnt[A[i]];
if ((Cnt[A[i]] & 1) == 0) ++Ans;
else if (Cnt[A[i]] != 1) --Ans;
}
for (int i = l; i <= r; ++i) --Cnt[A[i]];
}
else {
Lx = L[x]; Ry = R[y];
Ans = f[x][y];
for (int i = l; i < Lx; ++i) {
++Cnt[A[i]];
G = Get(Lx, Ry, A[i]);
if (((Cnt[A[i]] + G) & 1) == 0) ++Ans;
else if (Cnt[A[i]] + G != 1) --Ans;
}
for (int i = r; i > Ry; --i) {
++Cnt[A[i]];
G = Get(Lx, Ry, A[i]);
if (((Cnt[A[i]] + G) & 1) == 0) ++Ans;
else if (Cnt[A[i]] + G != 1) --Ans;
}
for (int i = l; i < Lx; ++i) --Cnt[A[i]];
for (int i = r; i > Ry; --i) --Cnt[A[i]];
}
printf("%d\n", Ans);
}
return 0;
}

  

[BZOJ 2821] 作诗(Poetize) 【分块】的更多相关文章

  1. BZOJ 2821: 作诗(Poetize)( 分块 )

    分块,分成N^0.5块.O(N^1.5)预处理出sm[i][j]表示前i块中j的出现次数, ans[i][j]表示第i~j块的答案. 然后就可以O(N^0.5)回答询问了.总复杂度O((N+Q)N^0 ...

  2. BZOJ 2821作诗(Poetize) 分块

    Description 有一个长度为n的序列,序列每个元素的范围[1,c],有m个询问x y,表示区间[x,y]中出现正偶数次的数的种类数. Solution 大力分块解决问题. 把序列分块,f[i] ...

  3. 2821: 作诗(Poetize)

    2821: 作诗(Poetize) Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 1078  Solved: 348[Submit][Status] ...

  4. 【BZOJ2821】作诗(Poetize) 分块

    Description 神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗.由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次, ...

  5. [BZOJ 2821] 作诗

    Link: BZOJ 2821 传送门 Solution: 一道类似区间众数的经典分块 由于个数为偶数这样的条件不能支持快速合并 因此要先$O(n*sqrt(n))$预处理出$pre[i][j]$表示 ...

  6. bzoj 2821 作诗 分块

    基本思路和蒲公英一样 还是预处理出每两个块间的答案 询问时暴力跑两边的贡献 #include<cstdio> #include<cstring> #include<ios ...

  7. BZOJ2821 作诗(Poetize) 分块

    题意 算法 经验总结 代码 题意 不带修改,查询数列[1,n]中[l,r]内的出现正偶数次的数的个数, 数列中的数 <= 1e5, n <= 1e5, 强制在线 算法 ​ 查询的内容: 区 ...

  8. 【分块】BZOJ2821 作诗(Poetize)

    2821: 作诗(Poetize) Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 3265  Solved: 951[Submit][Status][ ...

  9. BZOJ2821 作诗(Poetize) 【分块】

    BZOJ2821 作诗(Poetize) Description 神犇SJY虐完HEOI之后给傻×LYD出了一题: SHY是T国的公主,平时的一大爱好是作诗. 由于时间紧迫,SHY作完诗之后还要虐OI ...

随机推荐

  1. 阿里云 centos 部署javaweb 应用

    今天在阿里云上部署了个javaweb应用,在此记录下步骤,以供下次使用. 服务器版本: 1.root登陆服务器 2.服务器安装FTP服务,或者直接使用winscp上传文件(简单),本文介绍安装FTP服 ...

  2. OpenCV与QT联合编译 分类: Eye_Detection ZedBoard OpenCV shell ubuntu 2014-11-08 18:54 143人阅读 评论(0) 收藏

    问题1:首先参考rainysky的博客,发现qmake时发生找不到目录,文件的错误,又找不到 qmake.conf 文件的写法.所以开始按照网上的程序修改 XXX.pro 文件. 问题2:使用QT C ...

  3. 嵌入式Linux系统Bootloader启动调试技术(回想)

    嵌入式系统搭建过程中,对于系统平台搭建project师最初的一步一般是移植Bootloader ,当然移植有几个级别,通常最常见的是參考的EVM 的硬件有了改动(如更改了FLASH ,更改了SDRAM ...

  4. mybatis0205 一对多查询 复杂

    查询所有用户信息,关联查询订单及订单明细信息及商品信息,订单明细信息中关联查询商品信息 1.1sql 主查询表:用户信息 关联查询:订单.订单明细,商品信息 SELECT orders.*, user ...

  5. Android进阶笔记03:Android应用中实现查看"附近的人"的功能

    1. 要实现" 附近的人" 这功能,然后就研究了下: (1)首先要做的就是要获取到自己当前位置的经纬度(编程获取手机GPS定位模块的信息,进而获取自己当前位置的经纬度) (2)然后 ...

  6. (转)ecshop产品详情页显示不清晰

    详情页面的商品图片的设置方法 后台商店设置-显示设置-显示设置(就是这里,商品图片宽度和高度设置的大点就行了,放大镜效果也清晰了) 按照您详情页面图片的实际显示大小来添写. 商品管理-图片批量处理,这 ...

  7. static 方法.

    If a subclass defines a static method with the same signature as a static method in the superclass, ...

  8. ContextSwitchDeadlock was detected Message(读取注册表时出现).

    google的时候,在StackOverflow中得到个暂时解决的方法: http://stackoverflow.com/questions/2797677/contextswitchdeadloc ...

  9. iOS英文 汉化,如调用相册,相机改“cancel”,“photos”为“取消”,“相机”

    调用系统相册.相机发现是英文的系统相簿界面后标题显示“photos”,但是手机语言已经设置显示中文,纠结半天,最终在info.plist设置解决问题. 只需要改三个地方: 1.plist文件中: 2. ...

  10. 不用Google Adsense的84个赚钱方法

    这是一个关于网络广告商和网络销售的汇总列表,可以用来为您的网站或博客赚点钱.广告商都是英文的,加入广告请确认其是否支持中国地区支持,不支持的话就不必加入了. Chitika : 购物中心旗帜广告. ( ...