莫队&&分块
今天兔哥讲了一波莫队,比较有趣,先加一个链接,这是她的教程
这里就不详细说了,其实就是两个指针来优化的暴力。一开始排序函数有问题,没用上莫队的核心思想:把查询区间先排序,第一关键字是左指针所在的区间(注意,不是大小),第二关键字是右指针的大小。
然后一点点模拟就行了,左指针向前就减,否则加。
这里有一道板子题
题目描述 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 ...
随机推荐
- JavaScript:颜色辨别
<script> //参考文章:http://www.cnblogs.com/xuechenlei/p/5940729.html //游戏页面:http://www.webhek.com/ ...
- NGINX+PHP-FPM7 FastCGI sent in stderr: “Primary script unknown”
https://www.cnblogs.com/hjqjk/p/5651275.html 一开始是Nginx打开网页显示一直是拒绝访问.查看nginx日志是报错显示我的题目,然后就各种搜索解决啊! 百 ...
- Django - 创建多对多及增加示例
创建多对多: 方式一: 自定义关系表 备注:自定义表Host.Application,通过自定义表,将表Host和Application进行关联(通过外键方式工): 执行语句:python manag ...
- 27.8 执行定时计算限制操作(Timer)
private static System.Threading.Timer s_Timer; static void Main() { Console.WriteLine("checking ...
- Linux内核同步:per_cpu变量
per cpu变量相关函数和宏 DEFINE_PER_CPU_SHARED_ALIGNED(type,name):静态分配per_cpu数组,数组名为name,结构类型为type DEFINE_PER ...
- 洛谷——P2342 叠积木
P2342 叠积木 题目大意: 给你一堆积木,排成一行,初始时每对积木都只有一个,支持两种操作 第一种是移动操作,格式为“移动X到Y的上面”.X和Y代表两块积木的编号,意思是将X所的那堆积 ...
- 【 Educational Codeforces Round 51 (Rated for Div. 2) F】The Shortest Statement
[链接] 我是链接,点我呀:) [题意] [题解] 先处理出来任意一棵树. 然后把不是树上的边处理出来 对于每一条非树边的点(最多21*2个点) 在原图上,做dijkstra 这样就能处理出来这些非树 ...
- windows下db2的一些使用心得(不含安装)
1.安装完成后开始菜单栏里会有一个 DB2 Command Window - Administrator 打开这个命令窗口 2.db2 db2,启动 3.list databse directory ...
- crontab定时任务安装、使用方法
本文介绍下,在linux中安装crontab的方法,以及crontab的具体用法,有需要的朋友参考下. 这里使用yum方式安装crontab: 复制代码代码示例: [root@CentOS ~]# ...
- noip模拟赛 解谜游戏
题目描述LYK进了一家古董店,它很想买其中的一幅画.但它带的钱不够买这幅画.幸运的是,老板正在研究一个问题,他表示如果LYK能帮他解出这个问题的话,就把这幅画送给它.老板有一个n*m的矩阵,他想找一个 ...