洛谷 题解 SP3267 【DQUERY - D-query】
今天机房讲了莫队。
但是蒟蒻我并没有听懂,所以晚上回家恶补,才弄明白莫队。
莫队是莫涛大神发明的,它的作用就是用优秀的复杂度求解于一些区间之间的操作,莫队其实就是一个优雅的暴力,它的复杂度是O(n sqrt(n));
以此题为例,其实这题和这题是一样的,不过P1972会卡莫队。
回到此题:
题意很直白,我就不多赘述;
思路1:
暴力,这题最朴素的作法无非就是从l到r扫一遍,用数组记下出现的数,然后求值:
#include<bits/stdc++.h>
using namespace std;
#define maxn 100010
bool flag[maxn];
int n, m, a[maxn], sum, ans, l, r, x, y;
int main()
{
//freopen("count.in","r",stdin);
//freopen("count.out","w",stdout);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++ i)
scanf("%d", &a[i]);
for(int i = 1; i <= m; ++ i)
{
scanf("%d%d%d%d", &l, &r, &x, &y);
memset(flag, 0, sizeof(flag));
sum = ans = 0;
for(int j = l; j <= r; ++ j)
if(a[j] >= x && a[j] <= y)
{
++ sum;
if(flag[a[j]] == 0)
{
flag[a[j]] = 1;
++ ans;
}
}
printf("%d %d\n", sum, ans);
}
return 0;
}
ans即为所求;
但是这种作法的复杂度是O(n*n)的,肯定过不了;
那么就需要一些优化:
我们用两个指针不断的移动到相应的区间;
int l = 0, r = 1;
然后在移动的时候,我们就不停的add,del;
如果要想右,就add;
否则,就del;
void add(int x)
{
if(cnt[a[x]] == 0)
++ now;
++ cnt[a[x]];
}
void del(int x)
{
-- cnt[a[x]];
if(cnt[a[x]] == 0)
-- now;
}
while(l < q[i].l)
del(l ++);
while(l > q[i].l)
add(-- l);
while(r < q[i].r)
add(++ r);
while(r > q[i].r)
del(r --);
就是上面这样,
这就是莫队?
不,还有一个地方,
我们来假设要查询的区间为[1, 10000000]呢?
那不一样还是没有优化。
所以莫队还要一个很重要的地方,就是排序;
该如何排序?
如果按左端点排序,那么右端点就会不好表示;
如果按右端点排序,那么左端点就会不好表示;
这个时候,分块大法万岁;
把长度为n的序列,分成sqrt(n)个块;
把查询区间按照左端点所在块的序号排个序,如果左端点所在块相同,再按右端点排序。
其实,蒟蒻我也不明白这为什么会快200多ms,但它就是会;
整个程序的复杂度为O(n * sqrt(n));
代码时间:
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000010
int n, m, a[maxn], cnt[maxn], ans[maxn], bein[maxn], l = 1, r, now;
struct node
{
int l, r, id;
}q[maxn];
bool cmp(node a, node b)
{
return bein[a.l] == bein[b.l] ? a.r < b.r : bein[a.l] < bein[b.l];
}
void add(int x)//加入操作 (右移
{
if(cnt[a[x]] == 0)
++ now;
++ cnt[a[x]];
}
void del(int x)//删除(左移
{
-- cnt[a[x]];
if(cnt[a[x]] == 0)
-- now;
}
void print(int x)//要从后往前输出,所以来递归输出
{
if(x / 10)
print(x / 10);
//printf("%d", x % 10);
putchar(x % 10 + '0');
//printf("K");
}
int main()
{
scanf("%d", &n);//输入
for(int i = 1; i <= ceil((double) n / sqrt(n)); ++ i)
for(int j = (i - 1) * sqrt(n) + 1; j <= i * sqrt(n); ++ j)
bein[j] = i;//这是分的块
for(int i = 1; i <= n; ++ i)
scanf("%d", &a[i]);//还是输入
scanf("%d", &m);//继续输入
for(int i = 1; i <= m; ++ i)
{
scanf("%d%d", &q[i].l, &q[i].r);//还要输入
q[i].id = i;//记录下序号,cmp中要用
}
sort(q + 1, q + m + 1, cmp);//排序
/*这种作法就不需要add和del
for(int i = 1; i <= m; ++i) {
int ql = q[i].l, qr = q[i].r;
while(l < ql) now -= !--cnt[aa[l++]];
while(l > ql) now += !cnt[aa[--l]]++;
while(r < qr) now += !cnt[aa[++r]]++;
while(r > qr) now -= !--cnt[aa[r--]];
ans[q[i].id] = now;
}
*/
for(int i = 1; i <= m; ++ i)
{
while(l < q[i].l)//l右移
del(l ++);
while(l > q[i].l)//l左移
add(-- l);
while(r < q[i].r)//r右移
add(++ r);
while(r > q[i].r)//r左移
del(r --);
ans[q[i].id] = now;
}
for(int i = 1; i <= m; ++ i)
{
print(ans[i]);//输出
printf("\n");//记得换行
}
return 0;
}
因为在本蒟蒻最开始学的时候没有懂,所以有拜读了WAMonster大佬的文章,可能在思路上会有部分相同,而且我也强力推荐这位大佬的博客,写的特别好。
洛谷 题解 SP3267 【DQUERY - D-query】的更多相关文章
- 洛谷 题解 UVA572 【油田 Oil Deposits】
这是我在洛谷上的第一篇题解!!!!!!!! 这个其实很简单的 我是一只卡在了结束条件这里所以一直听取WA声一片,详细解释代码里见 #include<iostream> #include&l ...
- 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV
意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...
- 洛谷 题解 P1600 【天天爱跑步】 (NOIP2016)
必须得说,这是一道难题(尤其对于我这样普及组205分的蒟蒻) 提交结果(NOIP2016 天天爱跑步): OJ名 编号 题目 状态 分数 总时间 内存 代码 / 答案文件 提交者 提交时间 Libre ...
- 洛谷题解P4314CPU监控--线段树
题目链接 https://www.luogu.org/problemnew/show/P4314 https://www.lydsy.com/JudgeOnline/problem.php?id=30 ...
- 洛谷/SPOJ SP3267 题解
若想要深入学习主席树,传送门. Description: 给定数列 \(\{a_n\}\) ,求闭区间 \([l,r]\) 的互异的个数. Method: 扫描序列建立可持续化线段树,若此元素是第一次 ...
- 洛谷题解 CF777A 【Shell Game】
同步题解 题目翻译(可能有童鞋没读懂题面上的翻译) 给你三张牌0,1,2. 最初选一张,然后依次进行n次交换,交换规则为:中间一张和左边的一张,中间一张和右边一张,中间一张和左边一张...... 最后 ...
- 洛谷题解 CF807A 【Is it rated?】
同步题解 题目 好吧,来说说思路: 1.先读入啦~(≧▽≦)/~啦啦啦 2.判断a[i]赛前赛后是否同分数,如果分数不同,则输出,return 0 . 3.如果同分数,则判断a[i]赛前(或赛后)是否 ...
- 洛谷题解 P1138 【第k小整数】
蒟蒻发题解了 说明:此题我用的方法为桶排(我翻了翻有人用了桶排只不过很难看出来,可能有些重复的,这个题只是作为一个专门的桶排来讲解吧) (不会算抄袭吧 ‘QWaWQ’) 简单来说(会的人跳过就行): ...
- 【洛谷题解】P2303 [SDOi2012]Longge的问题
题目传送门:链接. 能自己推出正确的式子的感觉真的很好! 题意简述: 求\(\sum_{i=1}^{n}gcd(i,n)\).\(n\leq 2^{32}\). 题解: 我们开始化简式子: \(\su ...
随机推荐
- dubbo监控安装
tar xf dubbo-monitor-simple-2.8.4-assembly.tar.gz cd dubbo-monitor-simple-2.8.4 vi conf/dubbo.proper ...
- IP网段的判断
一. OSI七层模型 表示 说明 作用 应用层 HTTP.ftp 协议 表示层 UTF-8 将应用层协议翻译成计算机可识别的语言 会话层 管理传输层 传输层 TCP/UDP 建立以及断开连接 网 ...
- PHP Laravel-包含你自己的帮助函数
你可能想创建一个在应用的任何地方都可以访问的函数,这个教程将帮你实现
- deepin 、 windows10,双系统安装
deepin . windows10,双系统安装: 首先,最好专门分一个盘用来存放deepin操作系统的安装位置(我这里分给它60个G). 1.在 http://rsync.deepin.com/de ...
- nyoj 12-喷水装置(二)(贪心)
12-喷水装置(二) 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:10 submit:30 题目描述: 有一块草坪,横向长w,纵向长为h,在它的橫 ...
- hdu 1530 Maximum Clique (最大包)
Maximum CliqueTime Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)T ...
- python:0
if __name__ == '__main__': r = Rectangle() 79 def __str__(self): 80 return "address:(%d, %d)&qu ...
- 如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
缓存雪崩 数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机. 比如一个雪崩的简单过程: 1.redis集群大面积故障 2.缓存失 ...
- Markdown学习笔记(一)
解决Markdown文件插入图片无法只能本地查看的问题 原因:图片的显示与图片地址关联,写入Markdown时用的本机地址,一旦上传到网络,地址就发生了变化,也就显示不了图片. 寻找免费的图床网站. ...
- 像黑客一样写博客–Pelican快速搭建静态博客
"像黑客一样写博客",通过文本编辑器(Markdown编辑器)即可实现写博客,而且是静态的,很神奇吧,这里的方案是Pelican. 为啥叫 Pelican 这么奇怪的名字 &quo ...