题目描述

输入

输出

样例输入

3 4
1 2 2
1 2 1 3
1 2 1 1
1 3 1 3
2 3 2 3

样例输出

2 2
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]作业——莫队+树状数组/莫队+分块的更多相关文章

  1. COGS.1822.[AHOI2013]作业(莫队 树状数组/分块)

    题目链接: COGS.BZOJ3236 Upd: 树状数组实现的是单点加 区间求和,采用值域分块可以\(O(1)\)修改\(O(sqrt(n))\)查询.同BZOJ3809. 莫队为\(O(n^{1. ...

  2. bzoj3236 作业 莫队+树状数组

    莫队+树状数组 #include<cstdio> #include<cstring> #include<iostream> #include<algorith ...

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

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

  4. BZOJ_3289_Mato的文件管理_莫队+树状数组

    BZOJ_3289_Mato的文件管理_莫队+树状数组 Description Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号 .为了防止他人 ...

  5. bzoj 3289: Mato的文件管理 莫队+树状数组

    3289: Mato的文件管理 Time Limit: 40 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description Mato同学 ...

  6. 51nod 1290 Counting Diff Pairs | 莫队 树状数组

    51nod 1290 Counting Diff Pairs | 莫队 树状数组 题面 一个长度为N的正整数数组A,给出一个数K以及Q个查询,每个查询包含2个数l和r,对于每个查询输出从A[i]到A[ ...

  7. 【BZOJ3460】Jc的宿舍(树上莫队+树状数组)

    点此看题面 大致题意: 一棵树,每个节点有一个人,他打水需要\(T_i\)的时间,每次询问两点之间所有人去打水的最小等待时间. 伪·强制在线 这题看似强制在线,但实际上,\(pre\ mod\ 2\) ...

  8. HihoCoder 1488 : 排队接水(莫队+树状数组)

    描述 有n个小朋友需要接水,其中第i个小朋友接水需要ai分钟. 由于水龙头有限,小Hi需要知道如果为第l个到第r个小朋友分配一个水龙头,如何安排他们的接水顺序才能使得他们等待加接水的时间总和最小. 小 ...

  9. BZOJ 3236 莫队+树状数组

    思路: 莫队+树状数组 (据说此题卡常数) yzy写了一天(偷笑) 复杂度有点儿爆炸 O(msqrt(n)logn) //By SiriusRen #include <cmath> #in ...

随机推荐

  1. Git认证方式https和ssh的原理及比较

    常见的代码托管平台GitHub.GitLab和BitBucket等,基本都会使用Git作为版本控制工具.平台一般都提供两种认证方式https和ssh.了解该过程能够更加自由的配置和使用,本文就来简单聊 ...

  2. 用VS2017进行移动开发(C#、VB.NET)——OfflineCameraButton控件,Smobiler移动开发

    OfflineCameraButton控件 一.          样式一 我们要实现上图中的效果,需要如下的操作: 从工具栏上的“Smobiler Components”拖动一个OfflineCam ...

  3. spring boot拦截器中获取request post请求中的参数

    最近有一个需要从拦截器中获取post请求的参数的需求,这里记录一下处理过程中出现的问题. 首先想到的就是request.getParameter(String )方法,但是这个方法只能在get请求中取 ...

  4. Dynamics 365 Customer Engagement中插件的调试

    微软动态CRM专家罗勇 ,回复319或者20190319可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 本文主要根据官方的教 ...

  5. Flutter项目之app升级方案

    题接上篇的文章的项目,还是那个空货管理app.本篇文章用于讲解基于Flutter的app项目的升级方案. 在我接触Flutter之前,做过一个比较失败的基于DCloud的HTML5+技术的app,做过 ...

  6. JMeter写入文件

    之前我们推文讨论过如何使用jmeter读取文件, 比如csv, txt文件读取, 只要配置csv数据文件, 即可非常容易的从文件中读取想要的数据,  但是如果数据已经从API或者DB中获取, 想存放到 ...

  7. 教你一步永久激活WebStorm2018

    工欲善其事必先利其器,我们在开发过程中,编辑器是我们提高开发效率及生产必备的工具,如何发现一个高效好用的编辑器是程序员必备的技能之一. 前端开发有众多编辑器 sublime.vscode.webstr ...

  8. 看到了必须要Mark啊,最全的编程中英文词汇对照汇总(里面有好几个版本的,每个版本从a到d的顺序排列)

    java:  第一章: JDK(Java Development Kit) java开发工具包 JVM(Java Virtual Machine) java虚拟机 Javac  编译命令 java   ...

  9. c++11の泛型算法

    一.泛型算法泛型算法这个概念是针对容器操作的,我们知道,c++11的顺序容器有vector,list,deque等,对于这些容器,c++11并没给出相应的增删改查方法,而是定义了一组泛型算法 一般的泛 ...

  10. Java中数组和集合的foreach操作编译后究竟是啥

    今天和同事在关于foreach编译后是for循环还是迭代器有了不同意见,特做了个Demo,了解一下. 是啥自己来看吧! public class Demo { public static void m ...