题目链接:https://loj.ac/problem/6285

其实一看到是离线,我就想用莫队算法来做,对所有询问进行分块,但是左右边界移动的时候,不会同时更新数字最多的数,只是后面线性的扫了一遍,所以还有百分之12的样例过不了。

然后看了别人分块,是先对所有零散的数字编号(这个应该是所谓离散化),用vector[i]存储编号为i的数字所有出现的位置,因为从0到n,所以里面的值是升序的,我们先对块与块之间数字最多的数进行计算(预处理),在查询的时候查询[l,r]之间的数,把区间分成三块,左边不完整的块,中间完整的块,后面不完整的块,对于不完整的块可以遍历每一个元素用二分查找相应编号的vector里面在这个范围的数字有多少,完整的块就直接把预处理的数字拿出来。我做这题超时无数次,建议就是尽量减少map的调用,在查找时对于找过的数字编号可以标记,下次不找,然后块的大小可以设成block=80,我做的时候就是因为map调用太多,块的大小一直是sqrt(n),然后一直超时。

代码比较丑:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 100010
int a[maxn],num[maxn],MAX[][],lump[maxn],val[maxn];//num计数,MAX记录块与块之间最多的数字对应编号
// lump记录组,val保存原始值
vector<int>ve[maxn];
bool vis[maxn];//标记
map<int,int>mp;
int n,m,k,t,block,id;
void cal(int x)//预处理
{
int count1=,max1=;
memset(num,,sizeof(num));
for(int i=(x-)*block+;i<=n;i++)
{
int s=a[i];
num[s]++;
if(num[s]>count1||num[s]==count1&&val[s]<val[max1])
{
count1=num[s];
max1=s;
}
MAX[x][lump[i]]=max1;
}
}
int ask(int x,int l,int r)//二分查找
{
return upper_bound(ve[x].begin(),ve[x].end(),r)-lower_bound(ve[x].begin(),ve[x].end(),l);
}
int find(int l,int r)
{
memset(vis,,sizeof(vis));
int ans=,count1=;
ans=MAX[lump[l]+][lump[r]-];
count1=ask(ans,l,r);
vis[ans]=true;//记录编号为ans的数字查找过
for(int i=l;i<=min(lump[l]*block,r);i++)
{
if(vis[a[i]])
continue;
vis[a[i]]=true;
int count2=ask(a[i],l,r);
if(count2>count1||count1==count2&&val[a[i]]<val[ans])
{
count1=count2;
ans=a[i];
}
}
if(lump[l]!=lump[r])
{
for(int i=(lump[r]-)*block+;i<=r;i++)
{
if(vis[a[i]])
continue;
vis[a[i]]=true;
int count2=ask(a[i],l,r);
if(count2>count1||count1==count2&&val[a[i]]<val[ans])
{
count1=count2;
ans=a[i];
}
}
}
return val[ans];
}
int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
int main()
{
scanf("%d",&n);
block=;//这里很多人都写了80,。。。。。。
id=;
for(int i=;i<=n;i++)
{
a[i]=read();
lump[i]=(i-)/block+;
if(mp[a[i]]==)
{
mp[a[i]]=++id;
val[id]=a[i];//保存原始值
}
a[i]=mp[a[i]];//这个是保存编号,减少map调用,之前我没有这个一直超时
ve[a[i]].push_back(i);
}
for(int i=;i<=lump[n];i++)
cal(i);
int l,r;
for(int j=;j<=n;j++)
{
l=read();
r=read();
printf("%d\n",find(l,r));
}
return ;
}

LibreOJ 6285. 数列分块入门 9的更多相关文章

  1. LOJ #6285. 数列分块入门 9-分块(查询区间的最小众数)

    #6285. 数列分块入门 9 内存限制:256 MiB时间限制:1500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 2   题目描述 给 ...

  2. LOJ6277~6285 数列分块入门

    Portals 分块需注意的问题 数组大小应为,因为最后一个块可能会超出的范围. 当操作的区间在一个块内时,要特判成暴力修改. 要清楚什么时候应该+tag[t] 数列分块入门 1 给出一个长为的数列, ...

  3. LibreOJ 6277. 数列分块入门 1 题解

    题目链接:https://loj.ac/problem/6277 题目描述 给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,单点查值. 输入格式 第一行输入一个数字 \( ...

  4. loj#6285 数列分块入门 9 ( 回 滚 )

    题目 :  链接 :https://loj.ac/problem/6285 题意:给出一个长为 n的数列,以及 n个操作,操作涉及询问区间的最小众数. 思路:虽然这不是一道 回滚莫队题,就是 暴力分块 ...

  5. LibreOJ 6277 数列分块入门 1(分块)

    题解:感谢hzwer学长和loj让本蒟蒻能够找到如此合适的入门题做. 这是一道非常标准的分块模板题,本来用打标记的线段树不知道要写多少行,但是分块只有这么几行,极其高妙. 代码如下: #include ...

  6. LibreOJ 6278. 数列分块入门 2 题解

    题目链接:https://loj.ac/problem/6278 题目描述 给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的元素个数. ...

  7. LOJ#6285. 数列分块入门 9

    有点难..... 要求区间众数,所以我可以先把区间分块,然后我预处理出从第 i 块到第 j 块的众数,用dp[i][j]记录下来. 因为需要知道众数的num值, 所以我可以用一个vector来保存每个 ...

  8. LibreOJ 6282. 数列分块入门 6

    题目链接:https://loj.ac/problem/6282 参考博客:http://www.cnblogs.com/stxy-ferryman/p/8560551.html 这里如果用数组的话元 ...

  9. LibreOJ 6277. 数列分块入门 2

    题目链接:https://loj.ac/problem/6278 参考博客:https://blog.csdn.net/qq_36038511/article/details/79725027 这题我 ...

随机推荐

  1. leetcode1010

    class Solution: def numPairsDivisibleBy60(self, time: 'List[int]') -> int: sums = 0 s = {} n = le ...

  2. selenium初次接触-1

    10月30日 web自动化测试的两种方式:模拟整个http客户端(压力测试,取代浏览器和人,直接和服务端进行交互),模拟用户操作(功能测试,取代人) selenium是自动化浏览器的工具包,可以用于各 ...

  3. WPF按钮响应函数中执行操作耗时较长时,UI 界面不能实时更新——问题原因与解决方案

    原因: 一般来说,一个WPF窗口程序,只有一个UI线程, 如果这个线程停在某个函数,UI将会被阻塞,所有其他的界面操作都不能即时响应. 解决方案: 新开一个线程来执行耗时较长的操作,以不阻塞UI.

  4. curl 超时设置<转>

    PHP cURL 的超时设置有两个 CURLOPT_CONNECTTIMEOUT 和 CURLOPT_TIMEOUT,他们的区别是: CURLOPT_CONNECTTIMEOUT 用来告诉 PHP 在 ...

  5. leetcode题解 candy

    要求的条件是: 1.每个人最少一个糖果. 2.相邻的小朋友,要保证,评分高的比评分低的糖果多. 如果从一侧扫描的话,容易确定的就是递增序列,只要上升1个就够了. 容易出现问题的就是:遇到下降期,或者相 ...

  6. 切换用户身份su与sudo

    普通用户切换到root用户的方式有:su和sudo. 1,su - (su为switch user,即切换用户的简写) 格式:su -l USERNAME(-l为login,即登陆的简写) -l可以将 ...

  7. SSL和TLS协议的区别

    SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层.SSL通过互相认证.使用数字签名确保完整性.使用加密确保私密性,以实现客户 ...

  8. 434. Number of Segments in a String

    原题: 434. Number of Segments in a String 解题: 刚看到题目时,觉得可以通过统计空格个数,但想想有可能会有多个空格的情况 思路: 一:遍历字符,if条件碰到非空格 ...

  9. delphi注册热键方法(一)

    uses windows,menus; ..... //声明 HotKey_Key: Word; HotKey_Shift: Word; procedure WMHotKey(var msg : Tm ...

  10. JavaScript中的setInterval用法

    setInterval动作的作用是在播放动画的时,每隔一定时间就调用函数,方法或对象.可以使用本动作更新来自数据库的变量或更新时间显示.setInterval动作的语法格式如下:setInterval ...