BZOJ3236[Ahoi2013]作业——莫队+树状数组/莫队+分块
题目描述
输入
输出
样例输入
1 2 2
1 2 1 3
1 2 1 1
1 3 1 3
2 3 2 3
样例输出
1 1
3 2
2 1
提示
N=100000,M=1000000
莫队+树状数组:
先考虑每次询问没有权值区间限制的情况,将询问离线排序,用一个数组记录答案,莫队即可。
但现在每次询问有了查询的权值区间,显然一个数组无法记录答案,我们用树状数组来记录答案。
对于第一问直接用树状数组即可,对于第二问先用数组记录每个权值是否出现过再用树状数组维护即可。
莫队时间复杂度是$O(mlog_{n}\sqrt{n})$,查询时间复杂度是$O(mlog_{n})$。
- #include<set>
- #include<map>
- #include<queue>
- #include<stack>
- #include<cmath>
- #include<cstdio>
- #include<vector>
- #include<bitset>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- #define ll long long
- using namespace std;
- struct lty
- {
- int l,r;
- int a,b;
- int num;
- }q[1000010];
- int ans1[1000010];
- int ans2[1000010];
- int v1[100010];
- int v2[100010];
- int t[100010];
- int s[100010];
- int n,m;
- int L,R;
- int block;
- inline bool cmp(lty x,lty y)
- {
- return (x.l/block)==(y.l/block)?x.r<y.r:x.l<y.l;
- }
- inline void add1(int x,int val)
- {
- for(int i=x;i<=100000;i+=i&-i)
- {
- v1[i]+=val;
- }
- }
- inline void add2(int x,int val)
- {
- for(int i=x;i<=100000;i+=i&-i)
- {
- v2[i]+=val;
- }
- }
- inline int ask1(int x)
- {
- int res=0;
- for(int i=x;i;i-=i&-i)
- {
- res+=v1[i];
- }
- return res;
- }
- inline int ask2(int x)
- {
- int res=0;
- for(int i=x;i;i-=i&-i)
- {
- res+=v2[i];
- }
- return res;
- }
- int main()
- {
- scanf("%d%d",&n,&m);
- block=(int)sqrt(n+0.5);
- block-=rand()%30;
- for(int i=1;i<=n;i++)
- {
- scanf("%d",&s[i]);
- }
- for(int i=1;i<=m;i++)
- {
- scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].a,&q[i].b);
- q[i].num=i;
- }
- sort(q+1,q+1+m,cmp);
- L=1;
- for(int i=1;i<=m;i++)
- {
- while(L>q[i].l)
- {
- L--;
- if(!t[s[L]])
- {
- add2(s[L],1);
- }
- t[s[L]]++;
- add1(s[L],1);
- }
- while(R<q[i].r)
- {
- R++;
- if(!t[s[R]])
- {
- add2(s[R],1);
- }
- t[s[R]]++;
- add1(s[R],1);
- }
- while(L<q[i].l)
- {
- if(t[s[L]]==1)
- {
- add2(s[L],-1);
- }
- t[s[L]]--;
- add1(s[L],-1);
- L++;
- }
- while(R>q[i].r)
- {
- if(t[s[R]]==1)
- {
- add2(s[R],-1);
- }
- t[s[R]]--;
- add1(s[R],-1);
- R--;
- }
- ans1[q[i].num]=ask1(q[i].b)-ask1(q[i].a-1);
- ans2[q[i].num]=ask2(q[i].b)-ask2(q[i].a-1);
- }
- for(int i=1;i<=m;i++)
- {
- printf("%d %d\n",ans1[i],ans2[i]);
- }
- }
莫队+分块:
可以发现莫队+树状数组的做法时间复杂度主要在双指针移动时对答案的维护。
我们将树状数组改成分块,那么单次移动指针时间复杂度为$O(1)$,而单次查询的时间复杂度是$O(\sqrt{n})$。
这样莫队的时间复杂度是$O(m\sqrt{n})$,查询的时间复杂度为$O(m\sqrt{n})$。
- #include<set>
- #include<map>
- #include<queue>
- #include<stack>
- #include<cmath>
- #include<cstdio>
- #include<vector>
- #include<bitset>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- #define ll long long
- using namespace std;
- struct lty
- {
- int l,r;
- int a,b;
- int num;
- }q[1000010];
- int ans1[1000010];
- int ans2[1000010];
- int sum1[100010];
- int sum2[100010];
- int v1[100010];
- int v2[100010];
- int t[100010];
- int s[100010];
- int n,m;
- int L,R;
- int block;
- inline bool cmp(lty x,lty y)
- {
- return (x.l/block)==(y.l/block)?x.r<y.r:x.l<y.l;
- }
- inline int get(int x)
- {
- return (x-1)/200+1;
- }
- inline void add1(int x,int val)
- {
- sum1[get(x)]+=val;
- v1[x]+=val;
- }
- inline void add2(int x,int val)
- {
- sum2[get(x)]+=val;
- v2[x]+=val;
- }
- inline int ask1(int l,int r)
- {
- int res=0;
- for(int i=get(l)+1;i<=get(r)-1;i++)
- {
- res+=sum1[i];
- }
- if(get(l)==get(r))
- {
- for(int i=l;i<=r;i++)
- {
- res+=v1[i];
- }
- return res;
- }
- for(int i=l;i<=min(n,get(l)*200);i++)
- {
- res+=v1[i];
- }
- for(int i=(get(r)-1)*200+1;i<=r;i++)
- {
- res+=v1[i];
- }
- return res;
- }
- inline int ask2(int l,int r)
- {
- int res=0;
- for(int i=get(l)+1;i<=get(r)-1;i++)
- {
- res+=sum2[i];
- }
- if(get(l)==get(r))
- {
- for(int i=l;i<=r;i++)
- {
- res+=v2[i];
- }
- return res;
- }
- for(int i=l;i<=min(n,get(l)*200);i++)
- {
- res+=v2[i];
- }
- for(int i=(get(r)-1)*200+1;i<=r;i++)
- {
- res+=v2[i];
- }
- return res;
- }
- int main()
- {
- scanf("%d%d",&n,&m);
- block=(int)sqrt(n+0.5);
- for(int i=1;i<=n;i++)
- {
- scanf("%d",&s[i]);
- }
- for(int i=1;i<=m;i++)
- {
- scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].a,&q[i].b);
- q[i].num=i;
- }
- sort(q+1,q+1+m,cmp);
- L=1;
- for(int i=1;i<=m;i++)
- {
- while(L>q[i].l)
- {
- L--;
- if(!t[s[L]])
- {
- add2(s[L],1);
- }
- t[s[L]]++;
- add1(s[L],1);
- }
- while(R<q[i].r)
- {
- R++;
- if(!t[s[R]])
- {
- add2(s[R],1);
- }
- t[s[R]]++;
- add1(s[R],1);
- }
- while(L<q[i].l)
- {
- if(t[s[L]]==1)
- {
- add2(s[L],-1);
- }
- t[s[L]]--;
- add1(s[L],-1);
- L++;
- }
- while(R>q[i].r)
- {
- if(t[s[R]]==1)
- {
- add2(s[R],-1);
- }
- t[s[R]]--;
- add1(s[R],-1);
- R--;
- }
- ans1[q[i].num]=ask1(q[i].a,q[i].b);
- ans2[q[i].num]=ask2(q[i].a,q[i].b);
- }
- for(int i=1;i<=m;i++)
- {
- printf("%d %d\n",ans1[i],ans2[i]);
- }
- }
BZOJ3236[Ahoi2013]作业——莫队+树状数组/莫队+分块的更多相关文章
- COGS.1822.[AHOI2013]作业(莫队 树状数组/分块)
题目链接: COGS.BZOJ3236 Upd: 树状数组实现的是单点加 区间求和,采用值域分块可以\(O(1)\)修改\(O(sqrt(n))\)查询.同BZOJ3809. 莫队为\(O(n^{1. ...
- bzoj3236 作业 莫队+树状数组
莫队+树状数组 #include<cstdio> #include<cstring> #include<iostream> #include<algorith ...
- BZOJ 3236: [Ahoi2013]作业(莫队+树状数组)
传送门 解题思路 莫队+树状数组.把求\([a,b]\)搞成前缀和形式,剩下的比较裸吧,用\(cnt\)记一下数字出现次数.时间复杂度\(O(msqrt(n)log(n)\),莫名其妙过了. 代码 # ...
- BZOJ_3289_Mato的文件管理_莫队+树状数组
BZOJ_3289_Mato的文件管理_莫队+树状数组 Description Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号 .为了防止他人 ...
- bzoj 3289: Mato的文件管理 莫队+树状数组
3289: Mato的文件管理 Time Limit: 40 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description Mato同学 ...
- 51nod 1290 Counting Diff Pairs | 莫队 树状数组
51nod 1290 Counting Diff Pairs | 莫队 树状数组 题面 一个长度为N的正整数数组A,给出一个数K以及Q个查询,每个查询包含2个数l和r,对于每个查询输出从A[i]到A[ ...
- 【BZOJ3460】Jc的宿舍(树上莫队+树状数组)
点此看题面 大致题意: 一棵树,每个节点有一个人,他打水需要\(T_i\)的时间,每次询问两点之间所有人去打水的最小等待时间. 伪·强制在线 这题看似强制在线,但实际上,\(pre\ mod\ 2\) ...
- HihoCoder 1488 : 排队接水(莫队+树状数组)
描述 有n个小朋友需要接水,其中第i个小朋友接水需要ai分钟. 由于水龙头有限,小Hi需要知道如果为第l个到第r个小朋友分配一个水龙头,如何安排他们的接水顺序才能使得他们等待加接水的时间总和最小. 小 ...
- BZOJ 3236 莫队+树状数组
思路: 莫队+树状数组 (据说此题卡常数) yzy写了一天(偷笑) 复杂度有点儿爆炸 O(msqrt(n)logn) //By SiriusRen #include <cmath> #in ...
随机推荐
- JAVA WEB快速入门之从编写一个JSP WEB网站了解JSP WEB网站的基本结构、调试、部署
接上篇<JAVA WEB快速入门之环境搭建>,在完成了环境搭建后(JDK.Tomcat.IDE),现在是万事具备,就差写代码了,今天就来从编写一个JSP WEB网站了解JSP WEB网站的 ...
- 基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
今天我们来盘一盘Socket通讯和WebSocket协议在即时通讯的小应用——聊天. 理论大家估计都知道得差不多了,小编也通过查阅各种资料对理论知识进行了充电,发现好多demo似懂非懂,拷贝回来又运行 ...
- nginx rewrite 实现URL跳转
最近工作中常常要改nginx配置,学习了nginx中rewrite的用法 URL跳转这里说的URL跳转就是用户在访问一个URL时将其跳转到另一个URL上.常见的应用场景是让多个域名跳转到同一个URL上 ...
- mysql 存储ip地址
mysql提供了两个方法来处理ip地址: inet_aton 把ip转为无符号整型(4-8位) inet_ntoa 把整型的ip转为电地址 插入数据前,先用inet_aton把ip地址转为整型,可以节 ...
- redis.conf常用配置说明
最近学了 Redis,在 Linux 上安装的,接下来就简单讲解一下修改 Redis 配置文件 修改密码: 新安装的 Redis 是默认没有密码的,可以给Redis设置一个密码 先进入 Redis 的 ...
- vue px 转rem
来自:https://www.cnblogs.com/wangqiao170/p/8652505.html 侵 删 每一个认真生活的人,都值得被认真对待 vue px转换为rem 前端开发中还原设 ...
- [C#学习笔记1]用csc.exe和记事本写一个C#应用程序
csc.exe是C#的命令行编译器(CSharpCompiler),可以编译C#源程序成可执行程序.它与Visual Studio等IDE(Integrated Development Environ ...
- 回归算法比较(线性回归,Ridge回归,Lasso回归)
代码: # -*- coding: utf-8 -*- """ Created on Mon Jul 16 09:08:09 2018 @author: zhen &qu ...
- C# 内插字符串与字符串复合格式
var name = "Tom"; ; string aa = string.Format("name:{0},age:{1}", name, age);//字 ...
- mysql表与表之间数据的转移
1.相同表结构 INSERT INTO table1 SELECT * FROM table2; 2.不同表结构 INSERT INTO table1(filed1,...,filedn) SELEC ...