莫队&&分块
今天兔哥讲了一波莫队,比较有趣,先加一个链接,这是她的教程
这里就不详细说了,其实就是两个指针来优化的暴力。一开始排序函数有问题,没用上莫队的核心思想:把查询区间先排序,第一关键字是左指针所在的区间(注意,不是大小),第二关键字是右指针的大小。
然后一点点模拟就行了,左指针向前就减,否则加。
这里有一道板子题
题目描述 HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入输出格式
输入格式: 第一行:一个整数N,表示项链的长度。 第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。 第三行:一个整数M,表示HH 询问的个数。 接下来M 行:每行两个整数,L 和R( ≤ L ≤ R ≤ N),表示询问的区间。 输出格式: M 行,每行一个整数,依次表示询问对应的答案。
直接贴代码(数据加强之后AC不了,但貌似所有的算法都AC不了?)
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
ll que[],n,m,bk;
struct node{
int ans;
int l,r;
};
node k[];
int pl = ,pr = ;
bool cmp(node a,node b)
{
if(a.l / bk != b.l / bk)
{
return a.l < b.l;
}
else
{
return a.r < b.r;
}
}
ll cnt[],num = ;
void add(int a)
{
if(!cnt[a])
num++;
cnt[a]++;
}
void del(int a)
{
cnt[a]--;
if(!cnt[a])
num--;
}
ll ans[];
int main()
{
cin>>n;
bk = ceil(sqrt(n));
for(int i = ;i <= n;i++)
{
scanf("%lld",&que[i]);
}
cin>>m;
for(int i = ;i <= m;i++)
{
scanf("%d%d",&k[i].l,&k[i].r);
k[i].ans = i;
}
sort(k + ,k + m + ,cmp);
for(int i = ;i <= m;i++)
{
while(pl < k[i].l)
del(que[pl++]);
while(pl > k[i].l)
add(que[--pl]);
while(pr > k[i].r)
del(que[pr--]);
while(pr < k[i].r)
add(que[++pr]);
ans[k[i].ans] = num;
}
for(int i = ;i <= m;i++)
{
printf("%lld\n",ans[i]);
}
return ;
}
还有一个题,是莫队的来源,好像莫队是队长从这一题的论文答辩发明的。
题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。 你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子。当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己选择。 然而数据中有L=R的情况,请特判这种情况,输出0/1。
输入输出格式
输入格式: 输入文件第一行包含两个正整数N和M。N为袜子的数量,M为小Z所提的询问的数量。接下来一行包含N个正整数Ci,其中Ci表示第i只袜子的颜色,相同的颜色用相同的数字表示。再接下来M行,每行两个正整数L,R表示一个询问。 输出格式: 包含M行,对于每个询问在一行中输出分数A/B表示从该询问的区间[L,R]中随机抽出两只袜子颜色相同的概率。若该概率为0则输出0/1,否则输出的A/B必须为最简分数。(详见样例) 输入输出样例
输入样例#1: 复制 6 4
1 2 3 3 3 2
2 6
1 3
3 5
1 6 输出样例#1: 复制 2/5
0/1
1/1
4/15
这个是计数,但是本质上没什么区别,上代码
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
ll que[],bk,n,m;
struct node{
int ans;
int l,r;
};
node k[];
ll pl = ,pr = ;
ll ava[],bvb[];
bool cmp(node a,node b)
{
if(a.l / bk == b.l / bk)
{
return a.r < b.r;
}
else
{
return a.l < b.l;
}
}
ll gcd(ll a,ll b)
{
ll p;
while(a % b != )
{
p = a % b;
a = b;
b = p;
}
return b;
}
ll cnt[],num = ;
void add(int a)
{
num -= cnt[a] * cnt[a];
cnt[a]++;
num += cnt[a] * cnt[a];
}
void del(int a)
{
num -= cnt[a] * cnt[a];
cnt[a]--;
num += cnt[a] * cnt[a];
}
ll ans[],aa,bb,cc;
int main()
{
cin>>n>>m;
for(int i = ;i <= n;i++)
{
scanf("%lld",&que[i]);
}
bk = ceil(sqrt(n));
for(int i = ;i <= m;i++)
{
scanf("%d%d",&k[i].l,&k[i].r);
k[i].ans = i;
}
sort(k + ,k + m + ,cmp);
for(int i = ;i <= m;i++)
{
if(k[i].l == k[i].r)
{
ava[k[i].ans] = ;
bvb[k[i].ans] = ;
continue;
}
while(pl < k[i].l)
del(que[pl++]);
while(pl > k[i].l)
add(que[--pl]);
while(pr > k[i].r)
del(que[pr--]);
while(pr < k[i].r)
add(que[++pr]);
pl = k[i].l;
aa = num + k[i].l - k[i].r - ;
bb = (ll)(k[i].r - k[i].l + ) * (k[i].r - k[i].l);
cc = gcd(aa,bb);
aa /= cc;bb /= cc;
ava[k[i].ans] = aa;
bvb[k[i].ans] = bb;
// cout<<aa<<"/"<<cc<<endl;
}
for(int i = ;i <= m;i++)
{
printf("%lld/%lld\n",ava[i],bvb[i]);
}
return ;
}
但是莫队的修改好像复杂度不是很优秀,而且不能在线只能离线处理,所以我又学了一个其他的结构:分块
再附上一个链接,讲的超级好:
其实这种东西和线段树区别不大,但是线段树好像复杂度更好?
然后去钢了一道黑题,做的怀疑人生,最后抄代码过的
题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢。不过奶奶说他是很难受的时候才做出这样的事的…… 最近村子里长出了一大片一大片的蒲公英。一刮风,这些蒲公英就能飘到好远的地方了呢。我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢! 哥哥你要快点回来哦! 爱你的妹妹 Violet Azure 读完这封信之后微笑了一下。 “蒲公英吗……”
题目描述 在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。 为了简化起见,我们把所有的蒲公英看成一个长度为n的序列 (a1,a2..an)(a_1,a_2..a_n)(a1,a2..an) ,其中 aia_iai 为一个正整数,表示第i棵蒲公英的种类编号。 而每次询问一个区间 [l,r],你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。 注意,你的算法必须是在线的
输入输出格式
输入格式: 第一行两个整数 n,m ,表示有n株蒲公英,m 次询问。 接下来一行n个空格分隔的整数 aia_iai ,表示蒲公英的种类 再接下来m 行每行两个整数 l0,r0l_0,r_0l0,r0 ,我们令上次询问的结果为 x(如果这是第一次询问, 则 x=)。 令 l=(l0+x−)modn+,r=(r0+x−)modn+1l=(l_0+x-)\bmod n + ,r=(r_0+x-) \bmod n + 1l=(l0+x−)modn+,r=(r0+x−)modn+ ,如果 l>r,则交换 l,r 。 最终的询问区间为[l,r]。 输出格式: 输出m 行。每行一个整数,表示每次询问的结果。
这个题的思路不算难,就是离散化+分块处理在线找众数,但是代码真是狗
#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
int n,m,blo,id;
int v[],bl[];
int f[][]; //f[i][j]表示i~j的众数是多少
map<int,int>mp;
int val[],cnt[];
vector<int>ve[];
void pre(int x)
{
memset(cnt,,sizeof(cnt));
int mx = ,ans = ;
for(int i=(x - ) * blo + ;i <= n;i++)
{
cnt[v[i]]++;
int t = bl[i];
if(cnt[v[i]] > mx || (cnt[v[i]] == mx && val[v[i]] < val[ans])) //找x~t真正的众数
ans = v[i],mx = cnt[v[i]];
f[x][t] = ans;
}
}
int query(int l,int r,int x)
{
int t = upper_bound(ve[x].begin(),ve[x].end(),r) - lower_bound(ve[x].begin(),ve[x].end(),l);
return t;
}
int query(int a,int b)
{
int ans,mx;
ans = f[bl[a] + ][bl[b] - ];
mx = query(a,b,ans); //整区间里的众数
for(int i = ;i <= min(blo * bl[a],b);i++)
{
int t = query(a,b,v[i]);
if(t > mx || (t == mx && val[v[i]] < val[ans]))
{
ans = v[i];
mx = t;
}
}
if(bl[a] != bl[b])
{
for(int i = (bl[b] - ) * blo + ;i <= b;i++)
{
int t = query(a,b,v[i]);
if(t > mx || (t == mx && val[v[i]] < val[ans]))
ans = v[i],mx = t;
}
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
blo = ;
int ans = ;
for(int i = ;i <= n;i++)
{
scanf("%d",&v[i]);
if(!mp[v[i]])
{
mp[v[i]] = ++id; //离散化
val[id] = v[i]; //第一次出现的位置
}
v[i] = mp[v[i]];
ve[v[i]].push_back(i);
}
for(int i = ;i <= n;i++) //处理i在第几个块
bl[i] = (i - ) / blo + ;
for(int i = ;i <= bl[n];i++) //预处理f数组
pre(i);
for(int i = ;i <= m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
a = (a + ans - ) % n + ;
b = (b + ans - ) % n + ;
if(a > b)
swap(a,b);
ans = val[query(a,b)];
printf("%d\n",ans);
}
return ;
}
大家加油!!!
莫队&&分块的更多相关文章
- Bzoj 3236: [Ahoi2013]作业 莫队,分块
3236: [Ahoi2013]作业 Time Limit: 100 Sec Memory Limit: 512 MBSubmit: 1113 Solved: 428[Submit][Status ...
- [BZOJ 3585] mex 【莫队+分块】
题目链接:BZOJ - 3585 题目分析 区间mex,即区间中没有出现的最小自然数. 那么我们使用一种莫队+分块的做法,使用莫队维护当前区间的每个数字的出现次数. 然后求mex用分块,将权值分块(显 ...
- BZOJ_3585_mex && BZOJ_3339_Rmq Problem_莫队+分块
BZOJ_3585_mex && BZOJ_3339_Rmq Problem_莫队+分块 Description 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一 ...
- BZOJ_3809_Gty的二逼妹子序列 && BZOJ_3236_[Ahoi2013]作业 _莫队+分块
BZOJ_3809_Gty的二逼妹子序列 && BZOJ_3236_[Ahoi2013]作业 _莫队+分块 Description Autumn和Bakser又在研究Gty的妹子序列了 ...
- BZOJ3236[Ahoi2013]作业——莫队+树状数组/莫队+分块
题目描述 输入 输出 样例输入 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 ...
- CFGym101138D Strange Queries 莫队/分块
正解:莫队/分块 解题报告: 传送门 ummm这题耗了我一天差不多然后我到现在还没做完:D 而同机房的大佬用了一个小时没有就切了?大概这就是大佬和弱鸡的差距趴QAQ 然后只是大概写下思想好了因为代码我 ...
- [BZOJ3585]mex(莫队+分块)
显然可以离线主席树,这里用莫队+分块做.分块的一个重要思想是实现修改与查询时间复杂度的均衡,这里莫队和分块互相弥补. 考虑暴力的分块做法,首先显然大于n的数直接忽略,于是将值域分成sqrt(n)份,每 ...
- 小Z的袜子(莫队分块)题解
小Z的袜子(hose) 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜 ...
- 【CodeForces】700 D. Huffman Coding on Segment 哈夫曼树+莫队+分块
[题目]D. Huffman Coding on Segment [题意]给定n个数字,m次询问区间[l,r]的数字的哈夫曼编码总长.1<=n,m,ai<=10^5. [算法]哈夫曼树+莫 ...
- 莫队+分块 BZOJ 3809
3809: Gty的二逼妹子序列 Time Limit: 80 Sec Memory Limit: 28 MBSubmit: 1634 Solved: 482[Submit][Status][Di ...
随机推荐
- JS——缓慢动画封装
在知道如何获取内嵌式和外链式的标签属性值之后,我们再次封装缓慢动画: 单个属性 <!DOCTYPE html> <html> <head lang="en&qu ...
- JS——scroll
scrollWidth:父div宽度小于子div宽度,父div scrollWidth宽度为子div的宽度,大于则为本身的宽度width+padding scrollHeight:父div高度小于子d ...
- CSS——半透明
1.opacity:不仅背景半透明,内部其他元素也半透明 2.rgba():只有背景半透明. <!DOCTYPE html> <html lang="en"> ...
- 获取qq音乐json数据---某课网音乐app学习
移动端qq音乐地址:https://m.y.qq.com/ .抓取QQ音乐数据 请求首页时,有如下链接,回调了jsonp https://c.y.qq.com/splcloud/fcgi-bin/p. ...
- 2016.01.08 Javascript视频
完成JavaScript开发视频课程的Ajax部分内容.
- PHP 魔术方法浅谈
php中把以两个下划线(__)开头的方法称之为魔术方法.魔术方法包括: __construct() 类的构造方法 构建方法时被调用 __destruct() 类的析构方法 明确销毁 ...
- IO编程——复制一个文件中的内容到另一个文件
public class TestIO { public static void main(String[] args) { File inputFile = new File("a.txt ...
- HDU - 5894 Pocky(概率)
HDU5894—Pocky Problem Description: Let’s talking about something of eating a pocky. Here is a Decore ...
- Django-----中间件Cookie
Cookie: 用来跟踪用户的会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份. Cookie机制 ...
- 关于单片机编程里面调用sprintf死机的解决方法及原因分析
好久之前的做的笔记,这里贴出. char String[100];//直接用数组代替指针即可解决 下面代代码下载至单片机中,发现会出现单片机死机问题 #include "stdio.h&qu ...