传送门

Description

此时己是凌晨两点,刚刚做了Codeforces的小A掏出了英语试卷。英语作业其实不算多,一个小时刚好可以做完。然后是一个小时可以做完的数学作业,接下来是分别都是一个小时可以做完的化学,物理,语文......小A压力巨大。

这是小A碰见了一道非常恶心的数学题,给定了一个长度为n的数列和若干个询问,每个询问是关于数列的区间表示数列的第\(l\)个数到第\(r\)个数),首先你要统计该区间内大于等于\(a\),小于等于\(b\)的数的个数,其次是所有大于等于\(a\),小于等于\(b\)的,且在该区间中出现过的数值的个数。

小A望着那数万的数据规模几乎绝望,只能向大神您求救,请您帮帮他吧。

Input

第一行是两个正整数\(n,m\)

第二行\(n\)个数代表序列

接下来\(m\)行询问,每行四个整数\(l,r,a,b\)

Output

对每个询问输出一行两个用空格隔开的整数,分别代表答案

Hint

\(Forall:\)

\(1~\leq~n,m~\leq100000\)

Solution

多次查询没有修改,于是考虑莫队

一个非常显然的想法是对每个值的出现次数开桶,对第二问开权值桶,然后用树状数组维护前缀和,就可以做到单点修改区间查询了。复杂度\(O(n~\sqrt{n}~logm+mlogm)\),其中\(O(n~\sqrt{n}~logm)\)是修改复杂度,\(O(mlogm)\)是查询复杂度。于是发现前面一项复杂度过高,而后面一项完全不需要做到这样的复杂度。在一个操作复杂度过高,另一个操作复杂度压缩过度时,可以考虑将其中一个的复杂度降低,提升另一个的复杂度。比如这里考虑使用分块维护桶,单次修改复杂度\(O(1)\),查询复杂度\(O(\sqrt{n})\),总复杂度\(~O(~(n+m)~\sqrt{n}~)~\),可以通过本题

Code

#include<cmath>
#include<cstdio>
#include<algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a,b,c)
#endif
#define rg register
#define ci const int
#define cl const long long typedef long long int ll; template <typename T>
inline void qr(T &x) {
rg char ch=getchar(),lst=' ';
while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst == '-') x=-x;
} namespace IO {
char buf[120];
} template <typename T>
inline void qw(T x,const char aft,const bool pt) {
if(x < 0) {x=-x,putchar('-');}
rg int top=0;
do {IO::buf[++top]=x%10+'0';} while(x/=10);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
} const int maxn = 100010; int n,m;
int MU[maxn],belong[maxn],sa[maxn],bsa[maxn],sb[maxn],bsb[maxn]; struct Ask {
int l,r,a,b,num;
ll ans1,ans2;
inline bool operator<(const Ask &_others) const {
if(belong[this->l] != belong[_others.l]) return this->l < _others.l;
if(belong[this->l] & 1) return this->r < _others.r;
return this->r > _others.r;
}
};
Ask ask[maxn]; inline bool cmp(const Ask &_a,const Ask &_b) {
return _a.num < _b.num;
} int main() {
qr(n);qr(m);
for(rg int i=1;i<=n;++i) qr(MU[i]);
for(rg int i=1;i<=m;++i) {
qr(ask[i].l);qr(ask[i].r);qr(ask[i].a);qr(ask[i].b);ask[i].num=i;
}
for(rg int i=1,sn=sqrt(n);i<=n;++i) belong[i]=i/sn;
std::sort(ask+1,ask+1+m);
int prel=ask[1].l,prer=ask[1].l-1;
for(rg int i=1;i<=m;++i) { int l=ask[i].l,r=ask[i].r;
while(prel < l) {
if(!(--sa[MU[prel]])) --sb[MU[prel]],--bsb[belong[MU[prel]]];
--bsa[belong[MU[prel]]];
++prel;
}
while(prel > l) {
--prel;
if(!sa[MU[prel]]) ++sb[MU[prel]],++bsb[belong[MU[prel]]];
++bsa[belong[MU[prel]]];++sa[MU[prel]];
}
while(prer < r) {
++prer;
if(!sa[MU[prer]]) ++sb[MU[prer]],++bsb[belong[MU[prer]]];
++bsa[belong[MU[prer]]];++sa[MU[prer]];
}
while(prer > r) {
if(!(--sa[MU[prer]])) --sb[MU[prer]],--bsb[belong[MU[prer]]];
--bsa[belong[MU[prer]]];
--prer;
}
ll &ans1=ask[i].ans1,&ans2=ask[i].ans2;
int &a=ask[i].a,&b=ask[i].b;
int bl=belong[ask[i].a],br=belong[ask[i].b];
if(bl == br) {
for(rg int i=a;i<=b;++i) ans1+=sa[i],ans2+=sb[i];
continue;
}
for(rg int i=bl+1;i<br;++i) ans1+=bsa[i],ans2+=bsb[i];
for(rg int i=a;belong[i] == bl;++i) ans1+=sa[i],ans2+=sb[i];
for(rg int i=b;belong[i] == br;--i) ans1+=sa[i],ans2+=sb[i];
}
std::sort(ask+1,ask+1+m,cmp);
for(rg int i=1;i<=m;++i) {
qw(ask[i].ans1,' ',true);
qw(ask[i].ans2,'\n',true);
}
return 0;
}

Summary

修改复杂度过高,查询复杂度压缩过度时,考虑使用分块平衡复杂度。

【分块,莫队】【P4396】【AHOI2013】作业的更多相关文章

  1. 【BZOJ-3809】Gty的二逼妹子序列 分块 + 莫队算法

    3809: Gty的二逼妹子序列 Time Limit: 80 Sec  Memory Limit: 28 MBSubmit: 1072  Solved: 292[Submit][Status][Di ...

  2. 2018.11.07 NOIP训练 L的鞋子(权值分块+莫队)

    传送门 乱搞题. 我直接对权值分块+莫队水过了. 不过调了30min30min30min发现ststst表挂了是真的不想说什么233. 代码

  3. HDU 5145 分块 莫队

    给定n个数,q个询问[l,r]区间,每次询问该区间的全排列多少种. 数值都是30000规模 首先考虑计算全排列,由于有同种元素存在,相当于每次在len=r-l+1长度的空格随意放入某种元素即$\bin ...

  4. bzoj 3585 mex - 线段树 - 分块 - 莫队算法

    Description 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. Input 第一行n,m. 第二行为n个数. 从第三行开始,每行一个询问 ...

  5. bzoj 3236: 洛谷 P4396: [AHOI2013]作业 (莫队, 分块)

    题目传送门:洛谷P4396. 题意简述: 给定一个长度为\(n\)的数列.有\(m\)次询问,每次询问区间\([l,r]\)中数值在\([a,b]\)之间的数的个数,和数值在\([a,b]\)之间的不 ...

  6. P4396 [AHOI2013]作业 分块+莫队

    这个题正解是莫队+树状数组,但是我个人非常不喜欢树状数组这种东西,所以决定用分块来水这个题.直接在莫队维护信息的时候,维护单点同时维护块内信息就行了. 莫队就是这几行核心代码: void add(in ...

  7. 【BZOJ2038】【2009国家集训队】小Z的袜子(hose) 分块+莫队

    Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜 ...

  8. BZOJ.3809.Gty的二逼妹子序列(分块 莫队)

    题目链接 /* 25832 kb 26964 ms 莫队+树状数组:增加/删除/查询 都是O(logn)的,总时间复杂度O(m*sqrt(n)*logn),卡不过 莫队+分块:这样查询虽然变成了sqr ...

  9. 分块+莫队||BZOJ3339||BZOJ3585||Luogu4137||Rmq Problem / mex

    题面:P4137 Rmq Problem / mex 题解:先莫队排序一波,然后对权值进行分块,找出第一个没有填满的块,直接for一遍找答案. 除了bzoj3339以外,另外两道题Ai范围都是1e9. ...

  10. 【BZOJ 2120】数颜色【分块/莫队】

    题意 给出n个数字和m个操作.操作有两种.1:查询区间[l,r]内不同种类得数字个数.2: 将下标为p得数字修改为v 分析 如果不是修改操作的话,用莫队贼简单就可以水过,但是因为带了修改就有一些麻烦了 ...

随机推荐

  1. cookie,session傻傻分不清楚?

    做了这么多年测试,还是分不清什么是cookie,什么是session?很正常,很多初级开发工程师可能到现在都搞不清什么是session,cookie相对来说会简单很多. 下面这篇文章希望能够帮助大家分 ...

  2. day06 再谈编码 and 作业讲解

    1. 小数据池,(其他语言又叫常量池) id() 查看变量的内存地址 is和== is 判断内存地址是否一致 == 判断内容是否一致 小数据池的作用: 为了快速的创建字符串对象, 可以减少内存的浪费 ...

  3. MobSF 框架安装使用部署

    1.MobSF 简介 MobSF是Mobile Security Framework的缩写,这是一款智能化的开源移动应用(Android.IOS.Windows)测试框架,可以对应用进行动态.静态分析 ...

  4. ASP.NET 异步Web API + jQuery Ajax 文件上传代码小析

    该示例中实际上应用了 jquery ajax(web client) + async web api 双异步. jquery ajax post $.ajax({ type: "POST&q ...

  5. javascript event对象操作

    js代码: $(".leads_detail").click(function(e){ e = e || event; var t = e.target || e.srcEleme ...

  6. Intense Heat(前缀和或尺取)

    The heat during the last few days has been really intense. Scientists from all over the Berland stud ...

  7. P4语法(5) Package

    Package 对于package这个概念,类似于将一个框架中各组成部件以一个规律进行打包,以正常运转. 基于一个架构去编写一个新的pipeline的时候,需要先了解初始化的时候需要提供那些东西,pa ...

  8. hdu 1241--入门DFS

    Oil Deposits Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tot ...

  9. Linux基础语句总结

    看的视频是bilibili的网址如下:https://www.bilibili.com/video/av18069261/?p=36 然后做了点总结,可能有错误也可能有遗漏,同时参考了他人的资料. 系 ...

  10. MDL

    1 先是mdl的数据结构. 2 下面根据用法逐步的讲解mdl数据结构的含义:一般用法,先是 IoAllocateMdl :原型为: 最常用的是VirtualAddress和Length.把自己的Non ...