[CSP-S模拟测试]:ants(回滚莫队)
题目描述
然而贪玩的$dirty$又开始了他的第三个游戏。
$dirty$抓来了$n$只蚂蚁,并且赋予每只蚂蚁不同的编号,编号从$1$到$n$。最开始,它们按某个顺序排成一列。现在$dirty$想要进行$m$场比赛,每场比赛给出$l$和$r$,表示选出从左向右数第$l$只至第$r$只蚂蚁。被选出的蚂蚁需要快速地按编号从小到大排序,之后这些蚂蚁中编号连续的蚂蚁将围成一个圈。每场比赛结束后,蚂蚁们还需要快速地回到最开始的位置。
按照蚂蚁的审美标准,围成的圈越大美观值就越大。于是$dirty$每次需要找到最大的圈,但由于比赛多到难以处理,他只需要知道这个圈中蚂蚁的数目。
输入格式
第一行为两个整数$n,m$,分别表示蚂蚁的总数和比赛场数。
接下来一行$n$个数,表示从左向右依次的蚂蚁编号。
再接下来$m$行,每行两个数$l$、$r$,表示将从左向右数第$l$只至第$r$只蚂蚁选出进行比赛。
输出格式
输出$m$行,每行一个整数表示该次询问的答案。
样例
样例输入:
8 3
3 1 7 2 5 8 6 4
1 4
5 8
1 7
样例输出:
3
3
4
数据范围与提示
对于$20\%$的数据,$n\leqslant 500,m\leqslant 500$;
对于$50\%$的数据,$n\leqslant 30,000,m\leqslant 30,000$;
对于$100\%$的数据,$n\leqslant 100,000,m\leqslant 100,000$。
题解
这道题其实就是$permu$的数据加强版。
超想先讲一下我考场上的思路。
首先想到了莫队,然后用线段树维护最长的连续编号,实现起来不难,时间复杂度:$\Theta(n\sqrt{n}\log n)$,然而极限数据跑了$7$秒多(听说我的还是快的……),但是这种做法可以卡过$permu$。
现在来讲正解,考虑换个思路维护,用并查集,因为颜色各不相同,合并的时候看一下左边和右边有没有,然后将其$size$相加即可,注意不要路径压缩就好了;但是删除操作复杂度较高,于是想到回滚莫队,然后这道题就没了……
不过正解是用链表代替的并查集(然而我不会……)
时间复杂度:$\Theta(n\sqrt{n}\times \omega)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
$50\%$算法:
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct rec{int l,r,pos,id;}q[100001];
int n,m;
int a[100001];
int ans[100001];
int tr[500000],lc[500000],rc[500000];
bool cmp(rec a,rec b){return (a.pos)^(b.pos)?a.l<b.l:(((a.pos)&1)?a.r<b.r:a.r>b.r);}
void pushup(int x,int l,int r)
{
tr[x]=max(tr[L(x)],tr[R(x)]);
int mid=(l+r)>>1;
if(lc[L(x)]==mid-l+1)lc[x]=lc[L(x)]+lc[R(x)];
else lc[x]=lc[L(x)];
if(rc[R(x)]==r-mid)rc[x]=rc[R(x)]+rc[L(x)];
else rc[x]=rc[R(x)];
if(rc[L(x)]&&lc[R(x)])tr[x]=max(tr[x],rc[L(x)]+lc[R(x)]);
}
void add(int x,int l,int r,int w)
{
if(l==r)
{
tr[x]=lc[x]=rc[x]=1;
return;
}
int mid=(l+r)>>1;
if(w<=mid)add(L(x),l,mid,w);
else add(R(x),mid+1,r,w);
pushup(x,l,r);
}
void del(int x,int l,int r,int w)
{
if(l==r)
{
tr[x]=lc[x]=rc[x]=0;
return;
}
int mid=(l+r)>>1;
if(w<=mid)del(L(x),l,mid,w);
else del(R(x),mid+1,r,w);
pushup(x,l,r);
}
int main()
{
scanf("%d%d",&n,&m);
int t=sqrt(n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].pos=(q[i].l-1)/t+1;
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
for(int i=q[1].l;i<=q[1].r;i++)
add(1,1,n,a[i]);
ans[q[1].id]=tr[1];
int l=q[1].l,r=q[1].r;
for(int i=2;i<=m;i++)
{
while(l>q[i].l)add(1,1,n,a[--l]);
while(r<q[i].r)add(1,1,n,a[++r]);
while(l<q[i].l)del(1,1,n,a[l++]);
while(r>q[i].r)del(1,1,n,a[r--]);
ans[q[i].id]=tr[1];
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
$100\%$算法:
#include<bits/stdc++.h>
using namespace std;
struct rec{int l,r,pos,id;}q[100001];
int n,m;
int a[100001];
int ans[100001];
int sta[100001],size[100001],fa[100001],res,top;
bool vis[100001];
bool cmp(rec a,rec b){return a.pos==b.pos?a.r<b.r:a.pos<b.pos;}
int find(int x){return x==fa[x]?x:find(fa[x]);}
void merge(int x,int y)
{
x=find(x);y=find(y);
if(x==y)return;
if(size[x]>size[y])x^=y^=x^=y;
fa[x]=y;
size[y]+=size[x];
sta[++sta[0]]=x;
}
void add(int x)
{
vis[x]=1;
if(vis[x-1])merge(x,x-1);
if(vis[x+1])merge(x,x+1);
res=max(res,size[find(x)]);
}
void del()
{
while(sta[0]>top)
{
size[find(sta[sta[0]])]-=size[sta[sta[0]]];
fa[sta[sta[0]]]=sta[sta[0]];
sta[0]--;
}
}
int main()
{
scanf("%d%d",&n,&m);
int t=sqrt(n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].pos=(q[i].l-1)/t+1;
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int l,r,pos;
for(int i=1;i<=m;i++)
{
if(q[i].pos!=q[i-1].pos)
{
for(int j=1;j<=n;j++)
{
fa[j]=j;
vis[j]=0;
size[j]=1;
}
res=sta[0]=0;
l=pos=q[i].pos*t+1;
r=l-1;
}
if(q[i].pos==(q[i].r-1)/t+1)
{
int now=1,maxn=1;
for(int j=q[i].l;j<=q[i].r;j++)sta[++sta[0]]=a[j];
sort(sta+1,sta+sta[0]+1);
for(int j=1;j<=sta[0];j++)
{
if(sta[j]==sta[j-1]+1&&j>1)now++;
else now=1;
maxn=max(maxn,now);
}
ans[q[i].id]=maxn;
sta[0]=0;
}
else
{
while(r<q[i].r)add(a[++r]);
int flag=res;
top=sta[0];
while(l>q[i].l)add(a[--l]);
ans[q[i].id]=res;
res=flag;
while(l<pos)vis[a[l++]]=0;
del();
}
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
rp++
[CSP-S模拟测试]:ants(回滚莫队)的更多相关文章
- loj#6517. 「雅礼集训 2018 Day11」字符串(回滚莫队)
传送门 模拟赛的时候纯暴力竟然骗了\(70\)分-- 首先对于一堆\(g\)怎么计算概率应该很好想,用总的区间数减去不合法的区间数就行了,简而言之对\(g\)排个序,每一段长为\(d\)的连续序列的区 ...
- LOJ.6504.[雅礼集训2018 Day5]Convex(回滚莫队)
LOJ 莫队.发现只需要维护前驱后继就可以了. 但是加入一个点需要找到它当前的前驱后继,很麻烦还带个\(\log\). 但是如果只有删除某个点,只需要更新一下它的前驱后继即可. 用回滚莫队就好惹. 撤 ...
- BZOJ.4241.历史研究(回滚莫队 分块)
题目链接 \(Description\) 长度为n的数列,m次询问,每次询问一段区间最大的 \(A_i*tm_i\) (重要度*出现次数) \(Solution\) 好像可以用莫队做,但是取max的操 ...
- 2018.09.26 bzoj5218: [Lydsy2017省队十连测]友好城市(回滚莫队)
传送门 比较简单的一道回滚莫队吧. 每次询问用bitset优化kosaraju统计答案. 就是有点难调. 然后向dzyo学长学习了回滚莫队的一种简洁的实现方式,就是直接建立一个sqrt(m)∗sqrt ...
- 2018.08.14 bzoj4241: 历史研究(回滚莫队)
传送们 简单的回滚莫队,调了半天发现排序的时候把m达成了n... 代码: #include<bits/stdc++.h> #define N 100005 #define ll long ...
- BZOJ4241:历史研究(回滚莫队)
Description IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. ...
- LOJ#6504. 「雅礼集训 2018 Day5」Convex(回滚莫队)
题面 传送门 题解 因为并不强制在线,我们可以考虑莫队 然而莫队的时候有个问题,删除很简单,除去它和前驱后继的贡献即可.但是插入的话却要找到前驱后继再插入,非常麻烦 那么我们把它变成只删除的回滚莫队就 ...
- bzoj4241: 历史研究(回滚莫队)
传送门 这是一个叫做回滚莫队的神奇玩意儿 是询问,而且不强制在线,就决定是你了莫队 如果是每次插入一个数是不是很简单? 然而悲剧的是我们莫队的时候不仅要插入数字还要删除数字 那么把它变成只插入不就行了 ...
- HihoCoder 1629 Graph (2017 ACM-ICPC 北京区域赛 C题,回滚莫队 + 启发式合并 + 可撤销并查集)
题目链接 2017 ACM-ICPC Beijing Regional Contest Problem C 题意 给定一个$n$个点$m$条边的无向图.现在有$q$个询问,每次询问格式为$[l, ...
随机推荐
- C#WebApi自动生成文档
1.效果图 2.在webApi项目,打开Nuget,搜索WebApiTestClient,安装WebApiTestClient,注意是给HelpPage的 3.打开引入WebApiTestClient ...
- while与格式化的练习
练习 判断下列逻辑语句的结果,一定要自己先分析 1)1 > 1 or 3 < 4 or 4 > 5 and 2 > 1 and 9 > 8 or 7 < 6 2)n ...
- nginx启动报错
nginx启动的时候报错 nginx: [emerg] invalid number of arguments in "root" directive in /etc/nginx/ ...
- 行内元素(例如)设置float之后才能用width调整宽度
因为只有块元素才会有物理属性,在css世界里边,有三种形态的东西, 1. 块元素. 特性:有物理属性,width,height写值起作用,而且要占据一行.2. 内联元素. 特性:没有物理属性.但是ma ...
- Quartus 中调用modelsim的流程及*.vt或*.vht自动生成
一.自动生成验证程序testbench的方法,setting-EDA Tool->simylation->选择对应的语言(verilog对应*.vt,VHDL对应*.vht)process ...
- ubuntu下安装3.6.5
1.下载python3.6.5安装包 地址:https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgz 解压:tar -xvzf Python-3 ...
- vim 修改复制过来的代码缩进
命令模式下 :1,9< //1至9行回退一个tab :1,9> //1至9行缩进一个tab 让不可打印字符心事出来::set list
- Codeforces 矩阵题 题单
Matrix CF 166E Tetrahedron dp方程设为 f[i] 最后在 D点,g[i] 表示最后不在D点.最后 g[] 可以通过矩阵加速数列求得,数据可以强化,复杂度 \(O(logn) ...
- JVM 程序计数器
程序计数器是一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转 ...
- java 中的编码
1.1字节=8位,1024字节=1KB2.16进制0x12345678,其二进制为00010010 00110100 01010110 01111000共4字节3.字节序:两个或多个字节存放的先后顺序 ...