题目链接: BZOJ - 3236   BZOJ - 3809

算法一:莫队

首先,单纯的莫队算法是很好想的,就是用普通的第一关键字为 l 所在块,第二关键字为 r 的莫队。

这样每次端点移动添加或删除一个数字,用树状数组维护所求的信息就是很容易的。由于这里有 logn复杂度,所以这样移动端点的复杂度还是挺高的。

于是 BZOJ-3236 的时限 100s,我的代码跑了 98s,险过......

Paste一个BZOJ-3236的纯莫队代码:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring> using namespace std; inline void Read(int &Num) {
char c; 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();
}
} const int MaxN = 100000 + 5, MaxM = 1000000 + 5; int n, m, BlkSize;
int A[MaxN], Cnt[MaxN], T1[MaxN], T2[MaxN]; struct Query
{
int l, r, a, b, Pos, e, Ans1, Ans2;
Query() {}
Query(int x, int y, int p, int q, int o) {
l = x; r = y; a = p; b = q; Pos = o;
}
bool operator < (const Query &q) const {
if (e == q.e) return r < q.r;
return e < q.e;
}
} Q[MaxM]; inline bool Cmp(Query q1, Query q2) {
return q1.Pos < q2.Pos;
} inline void Add1(int x, int Num) {
for (int i = x; i <= n; i += i & -i)
T1[i] += Num;
}
inline int Get1(int x) {
if (x == 0) return 0; //Notice!
int ret = 0;
for (int i = x; i; i -= i & -i)
ret += T1[i];
return ret;
} inline void Add2(int x, int Num) {
for (int i = x; i <= n; i += i & -i)
T2[i] += Num;
}
inline int Get2(int x) {
if (x == 0) return 0; //Notice!
int ret = 0;
for (int i = x; i; i -= i & -i)
ret += T2[i];
return ret;
} inline void Add_Num(int x) {
if (Cnt[x] == 0) Add2(x, 1);
++Cnt[x];
Add1(x, 1);
}
inline void Del_Num(int x) {
--Cnt[x];
Add1(x, -1);
if (Cnt[x] == 0) Add2(x, -1);
} void Pull(int f, int x, int y) {
if (x == y) return;
if (f == 0)
if (x < y)
for (int i = x; i < y; ++i) Del_Num(A[i]);
else
for (int i = x - 1; i >= y; --i) Add_Num(A[i]);
else
if (x < y)
for (int i = x + 1; i <= y; ++i) Add_Num(A[i]);
else
for (int i = x; i > y; --i) Del_Num(A[i]);
} int main()
{
Read(n); Read(m);
BlkSize = (int)sqrt((double)n);
for (int i = 1; i <= n; ++i) Read(A[i]);
int l, r, a, b;
for (int i = 1; i <= m; ++i) {
Read(l); Read(r); Read(a); Read(b);
Q[i] = Query(l, r, a, b, i);
Q[i].e = (l - 1) / BlkSize + 1;
}
sort(Q + 1, Q + m + 1);
memset(Cnt, 0, sizeof(Cnt));
memset(T1, 0, sizeof(T1));
memset(T2, 0, sizeof(T2));
for (int i = Q[1].l; i <= Q[1].r; ++i) Add_Num(A[i]);
Q[1].Ans1 = Get1(Q[1].b) - Get1(Q[1].a - 1);
Q[1].Ans2 = Get2(Q[1].b) - Get2(Q[1].a - 1);
for (int i = 2; i <= m; ++i) {
if (Q[i].r < Q[i - 1].l) {
Pull(0, Q[i - 1].l, Q[i].l);
Pull(1, Q[i - 1].r, Q[i].r);
}
else {
Pull(1, Q[i - 1].r, Q[i].r);
Pull(0, Q[i - 1].l, Q[i].l);
}
Q[i].Ans1 = Get1(Q[i].b) - Get1(Q[i].a - 1);
Q[i].Ans2 = Get2(Q[i].b) - Get2(Q[i].a - 1);
}
sort(Q + 1, Q + m + 1, Cmp);
for (int i = 1; i <= m; ++i) printf("%d %d\n", Q[i].Ans1, Q[i].Ans2);
return 0;
}

算法二:莫队+分块

这是一个神奇的做法,还是用莫队转移区间端点,但是每次移动端点都是O(1)的,不再用树状数组,而是将 [1,n] 的数值分成大小为 sqrt(n) 的块。

莫队时加入一个数,如果它之前不存在,就将它所在的块的数组值加一,删除时类似。

然后每个询问转移完区间之后用分块的方法查询答案,中间的整块直接查,两边的零散的数就暴力枚举,这样每个询问就是 sqrt(n) 的。

总复杂度也大约是 O(n^1.5) ,主要就是把移动区间端点变为了 O(1),十分神奇!

我用这个算法写了 3809,代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring> using namespace std; inline void Read(int &Num) {
char c; 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();
}
} const int MaxN = 100000 + 5, MaxM = 1000000 + 5, MaxBlk = 350 + 5; int n, m, BlkSize, TotBlk;
int A[MaxN], Cnt[MaxN], T[MaxBlk], L[MaxBlk], R[MaxBlk], Ans[MaxM], Blk[MaxN]; struct Query
{
int l, r, Index, a, b;
Query() {}
Query(int f, int x, int y, int p, int q) {
Index = f; l = x; r = y; a = p; b = q;
}
bool operator < (const Query &b) const {
if (Blk[l] == Blk[b.l]) return r < b.r;
return Blk[l] < Blk[b.l];
}
} Q[MaxM]; inline void Add_Num(int x) {
if (Cnt[x] == 0) ++T[Blk[x]];
++Cnt[x];
} inline void Del_Num(int x) {
--Cnt[x];
if (Cnt[x] == 0) --T[Blk[x]];
} void Pull(int f, int x, int y) {
if (x == y) return;
if (f == 0) {
if (x < y) for (int i = x; i < y; ++i) Del_Num(A[i]);
else for (int i = x - 1; i >= y; --i) Add_Num(A[i]);
}
else {
if (x < y) for (int i = x + 1; i <= y; ++i) Add_Num(A[i]);
else for (int i = x; i > y; --i) Del_Num(A[i]);
}
} int GetAns(int a, int b) {
int x, y, ret;
x = Blk[a]; if (L[x] != a) ++x;
y = Blk[b]; if (R[y] != b) --y;
ret = 0;
if (x > y) {
for (int i = a; i <= b; ++i)
if (Cnt[i] > 0) ++ret;
}
else {
for (int i = x; i <= y; ++i) ret += T[i];
for (int i = a; i < L[x]; ++i)
if (Cnt[i] > 0) ++ret;
for (int i = b; i > R[y]; --i)
if (Cnt[i] > 0) ++ret;
}
return ret;
} int main()
{
Read(n); Read(m);
for (int i = 1; i <= n; ++i) Read(A[i]);
BlkSize = (int)sqrt((double)n);
TotBlk = (n - 1) / BlkSize + 1;
for (int i = 1; i <= TotBlk; ++i) {
L[i] = (i - 1) * BlkSize + 1;
R[i] = i * BlkSize;
}
R[TotBlk] = n;
for (int i = 1; i <= n; ++i) Blk[i] = (i - 1) / BlkSize + 1;
int l, r, a, b;
for (int i = 1; i <= m; ++i) {
Read(l); Read(r); Read(a); Read(b);
Q[i] = Query(i, l, r, a, b);
}
sort(Q + 1, Q + m + 1);
memset(Cnt, 0, sizeof(Cnt));
memset(T, 0, sizeof(T));
for (int i = Q[1].l; i <= Q[1].r; ++i) Add_Num(A[i]);
Ans[Q[1].Index] = GetAns(Q[1].a, Q[1].b);
for (int i = 2; i <= m; ++i) {
if (Q[i].r < Q[i - 1].l) {
Pull(0, Q[i - 1].l, Q[i].l);
Pull(1, Q[i - 1].r, Q[i].r);
}
else {
Pull(1, Q[i - 1].r, Q[i].r);
Pull(0, Q[i - 1].l, Q[i].l);
}
Ans[Q[i].Index] = GetAns(Q[i].a, Q[i].b);
}
for (int i = 1; i <= m; ++i) printf("%d\n", Ans[i]);
return 0;
}

  

[BZOJ 3236] [Ahoi2013] 作业 && [BZOJ 3809] 【莫队(+分块)】的更多相关文章

  1. Bzoj 3236: [Ahoi2013]作业 莫队,分块

    3236: [Ahoi2013]作业 Time Limit: 100 Sec  Memory Limit: 512 MBSubmit: 1113  Solved: 428[Submit][Status ...

  2. BZOJ 3236: [Ahoi2013]作业( 莫队 + BIT )

    莫队..用两个树状数组计算.时间复杂度应该是O(N1.5logN). 估计我是写残了...跑得很慢... ----------------------------------------------- ...

  3. BZOJ 3236: [Ahoi2013]作业

    3236: [Ahoi2013]作业 Time Limit: 100 Sec  Memory Limit: 512 MBSubmit: 1393  Solved: 562[Submit][Status ...

  4. bzoj 3236: [Ahoi2013]作业(缺线段树)

    3236: [Ahoi2013]作业 Time Limit: 100 Sec  Memory Limit: 512 MBSubmit: 1744  Solved: 702[Submit][Status ...

  5. BZOJ 3236: [Ahoi2013]作业(莫队+树状数组)

    传送门 解题思路 莫队+树状数组.把求\([a,b]\)搞成前缀和形式,剩下的比较裸吧,用\(cnt\)记一下数字出现次数.时间复杂度\(O(msqrt(n)log(n)\),莫名其妙过了. 代码 # ...

  6. BZOJ 4129: Haruna’s Breakfast [树上莫队 分块]

    传送门 题意: 单点修改,求一条链的mex 分块维护权值,$O(1)$修改$O(S)$求mex...... 带修改树上莫队 #include <iostream> #include < ...

  7. BZOJ.4241.历史研究(回滚莫队 分块)

    题目链接 \(Description\) 长度为n的数列,m次询问,每次询问一段区间最大的 \(A_i*tm_i\) (重要度*出现次数) \(Solution\) 好像可以用莫队做,但是取max的操 ...

  8. Bzoj 3781: 小B的询问 莫队,分块,暴力

    3781: 小B的询问 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 426  Solved: 284[Submit][Status][Discuss ...

  9. 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

    [原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 Descri ...

随机推荐

  1. hdu 2546 饭卡(DP)

    很久以前做过这道题,晚上睡不着,看见nyist加了一个DP的比赛,就进来打个酱油. 这道题的点睛之笔是将最大值记录下来,然后将其值改为0.之后就是普通的背包了. #include<stdio.h ...

  2. ASP.NET通过http/https的POST方式,发送和接受XML文件内容

    本文转载:http://hi.baidu.com/ysyhyt/item/5011ae39ce3cf49fb80c0395 本文参考:http://blog.csdn.net/ououou123456 ...

  3. Android自己定义控件而且使其能够在xml中自己定义属性

    为什么要自己定义View android开发中自己定义View的优点是显而易见的.比方说以下的这个顶部导航,它被设计出如今应用的每一个界面,但每次的内容却不尽同样.我们不能在每一个layout资源中都 ...

  4. percona-MYSQLGUI监控

    1.https://www.percona.com/blog/2016/05/26/monitoring-with-percona-app-for-grafana/ http://pmmdemo.pe ...

  5. spring beans源码解读之--BeanFactory的注册

    beanFactory的继承关系如下图所示: (图片来源:http://www.myexception.cn/software-architecture-design/925888.html) 在上节 ...

  6. Android(java)学习笔记213:开源框架post和get方式提交数据(qq登录案例)

    1.前面提到Http的get/post方式  . HttpClient方式,实际工作的时候不常用到,因为这些方式编写代码是很麻烦的 2.Android应用会经常使用http协议进行传输,网上会有很完善 ...

  7. angularjs kindEditor 中自定义按钮 弹出dialog

    1.angular-kindeditor.js 第38行左右加 editorConfig.items = ["placehoder"]; 2.en.js 第234行 placeho ...

  8. string.Join和Reverse的简单使用示例

    String.Join 方法 (String, String[]) 串联字符串数组的所有元素,其中在每个元素之间使用指定的分隔符. 例如,如果 separator 为“,”且 value 的元素为“a ...

  9. 玩转CSLA.NET小技巧系列二:使用WCF无法上传附件,提示413 Entity Too Large

    背景:由于系统需要展示图片,客户上传图片到本地客户端目录,然后在数据库中存储本地图片地址,和图片二进制数据 错误原因:我是使用CSLA的WCF服务,使用了数据门户,WCF协议使用的是wsHttpBin ...

  10. OSX安装nginx和rtmp模块(rtmp直播服务器搭建)

    1.安装Homebrew,执行命令 1 ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/ma ...