[BZOJ 3236] [Ahoi2013] 作业 [BZOJ 3809] 【莫队(+分块)】

题目链接: 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;
}

  

转载于:https://www.cnblogs.com/JoeFan/p/4246291.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/459690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

武汉理工大学java,武汉理工大学 web技术基础

计算机网络是现代通信技术与计算机技术相结合的产物&#xff0c;Internet则是计算机网络的最具体的应用。Web服务是最主要的网络服务&#xff0c;几乎一提到Internet&#xff0c;就会想到Web技术。本课程将介绍互联网的发展历史&#xff0c;最新的科学进展&#xff0c;Web的工作…

mysql多实例

mysql的多实例有两种方式可以实现&#xff0c;两种方式各有利弊。第一种是使用多个配置文件启动不同的进程来实现多实例&#xff0c;这种方式的优势逻辑简单&#xff0c;配置简单&#xff0c;缺点是管理起来不太方便。第二种是通过官方自带的mysqld_multi使用单独的配置文件来实…

oracle闪回某个时间点的数据库,oracle11g 使用闪回查询恢复表到过去某一个时间点...

一、新建测试表并插入数据&#xff1a;oracle二、模拟表数据误删并提交&#xff1a;测试三、使用闪回查询来查误删前表的数据&#xff1a;(表误删是在15:08分左右误删&#xff0c;所以在15:08分以前表的数据仍是在的)&#xff1a;spa四、用如今的数据与误删前的数据作对比&…

opengl微开发之1-从零開始

对OpenGL有一点了解之后&#xff0c;如今開始真正编写代码。 今天的内容&#xff1a; 使用FreeGLUT创建OpenGL的上下文环境 初始化GLEW 创建一个OpenGL的的模板范例 第一步&#xff1a; 一个OpenGL的上下文能够同意我们传递命令究竟层硬件&#xff0c;所以须要一个上下文环境。…

Git客户端(Windows系统)的使用(Putty)(转)

本文环境&#xff1a; 操作系统&#xff1a;Windows XP SP3 Git客户端&#xff1a;TortoiseGit-1.8.14.0-32bit 一、安装Git客户端 全部安装均采用默认&#xff01; 1. 安装支撑软件 msysgit: http://msysgit.github.io/ 当前最新版本为v1.9.5。 2. 安装TortoiseGit 首先&#…

oracle只舍不入,Oracle常识基础(一)

一.Oracle数据类型1.字符数据类型.> char:可以存储字母数字值&#xff0c;长度在1到2000个字节。.> varchar2:存储可变长度的char类型字符串,大小在1到4000个字节范围内。.> long:存储可变长度的字符数据,最多存储2GB。long类型的使用限制&#xff1a;*********…

软件测试的误区

随着软件测试对提高软件质量重要性的不断提高&#xff0c;软件测试也不断受到重视。但是&#xff0c;国内软件测试过程的不规范&#xff0c;重视开发和轻视测试的现象依旧存在。因此&#xff0c;对于软件测试的重要性、测试方法和测试过程等方面都存在很多不恰当的认识&#xf…

Kubernetes用户指南(二)--部署组合型的应用、连接应用到网络中

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 https://blog.csdn.net/qq1010885678/article/details/49026825 一、部署组合型的应用1、使用配置文件启动replicas集合k8s通过Replication Controller来创建和管理各个不同的重复容器集合&#xff…

oracle指令df,​ oracle 常用命令大汇总

oracle常用命令大汇总第一章&#xff1a;日志管理1、forcing log switchessql> alter system switch logfile;2、forcing checkpointssql> alter system checkpoint;3、adding online redo log groupssql> alter database add logfile [group 4]sql> (/disk3/log4a…

时刻获取浏览器宽度

$(function(){$(window).resize(Nchwid);function Nchwid() {var widdocument.documentElement.clientWidth;console.log(wid); }}) 转载于:https://www.cnblogs.com/nc-blog/p/4250132.html

oracle 函数

运算符: 算数运算符: - * / 连接运算符 || e.g select a||b||c from dual; 比较运算符 >, , >, <, <, !, like, between and, is null, in 任何值与null进行运算 都为null ascii(a); 根据字符 返回编码值 chr(编…

oracle中defined,Oracle:专栏定义(Oracle: column ambigously defined)

Oracle&#xff1a;专栏定义(Oracle: column ambigously defined)我收到以下错误。 据我所知&#xff0c;所有列都是由表名定义的&#xff0c;所以我不明白为什么我从Oracle数据库中得到这个错误。OCIError: ORA-00918: column ambiguously defined: SELECT * FROM (SELECT raw…

两道二分coming~

第一道&#xff1a;poj 1905Expanding Rods 题意&#xff1a;两道墙&#xff08;距离L&#xff09;之间架一根棒子&#xff0c;棒子受热会变长&#xff0c;弯曲&#xff0c;长度变化满足公式&#xff08; s(1n*C)*L&#xff09;&#xff0c;求的是弯曲的高度h。 首先来看这个图…

include静态加载布局ViewStub动态加载布局

layout"layout/" 文件名.xml/> 他可以加载任何的layout如果是如果想加载一个控件&#xff0c;要把这个控件写在layout。xml文件里 ViewStub android:id"id/vsb" android:layout_width"match_parent" android:layout_height&qu…

oracle 返回表的函数,oracle 返回表函数

--首先创建一个类型create or replace type t_test as object( empno number(4), ename varchar2(20), job varchar2(20), sal number(7,2) ) ; ---创建一个对象&#xff0c;引用上面的类型t_test create or replace type t_test_table as table of t_t…

十天学Linux内核之第七天---电源开和关时都发生了什么

十天学Linux内核之第七天---电源开和关时都发生了什么 原文:十天学Linux内核之第七天---电源开和关时都发生了什么说实话感觉自己快写不下去了&#xff0c;其一是有些勉强跟不上来&#xff0c;其二是感觉自己越写越差&#xff0c;刚开始可能是新鲜感以及很多读者的鼓励&#xf…

dede php 里加nofollow,织梦导航栏目如何加nofollow

很多用织梦程序做网站的朋友会发现&#xff0c;dedecms后台并没有直接加nofollow的选项。那如果想要给联系我们、关于我们等导航栏目加上nofollow该怎么解决呢&#xff1f;笔者在网上也找了一些资料&#xff0c;有通过修改数据库增加参数的方法&#xff0c;但没有成功。今天笔者…

黄仕沛经方医案医话精选(上) 王晓军 整理

1:出奇兵而不奇&#xff5e; 顽 固 性 呃 逆 案苏某&#xff0c;男&#xff0c;55岁&#xff0c;藉贯潮州&#xff0c;香港商人。二年前&#xff0c;工作压力较大&#xff0c;后而呃逆发作&#xff0c;易中、西医十数&#xff0c;用镇静、解痉等&#xff0c;甚至抗抑郁药…

ubuntu 重启命令,ubuntu 重启网卡方法

ubuntu 重启命令 重启命令&#xff1a;1、reboot2、shutdown -r now 立刻重启(root用户使用)3、shutdown -r 10 过10分钟自动重启(root用户使用)4、shutdown -r 20:35 在时间为20:35时候重启(root用户使用)如果是通过shutdown命令设置重启的话&#xff0c;可以用shutdown -c命令…

【Cocos2d-Js实战教学(1)横版摇杆八方向移动】

本教程主要通过搭建一个横版摇杆八方向移动的实例&#xff0c;让大家如何用Cocos2dx-Js来做一款游戏&#xff0c;从基础了解Cocos2dx-Js的基本实现原理&#xff0c;从创建工程&#xff0c;到各个知识点的梳理。 教程分为上下两讲&#xff1a; 上讲有2个小节&#xff1a; 1&…