【BZOJ】4358: permu 莫队算法

【题意】给定长度为n的排列,m次询问区间[L,R]的最长连续值域。n<=50000。

【算法】莫队算法

【题解】考虑莫队维护增加一个数的信息:设up[x]表示数值x往上延伸的最大长度,down[x]表示数值x往下延伸的最大长度。

增加一个数x时,up[x]=up[x+1]+1,down[x]=down[x-1]+1。令t=up[x]+down[x]+1,可以用于更新答案。

同时,增加x后会影响到x所在连续区间最大数和最小数,中间的数字不会影响答案(只考虑加数),所以有:

down[x+up[x]-1] = up[x-down[x]+1] = t

按左端点分块,块内按右端点排序。为了保证莫队的复杂度,我们必须O(q)实现左端点的移动(q是块大小),O(n)实现整块的右端点移动。

记块的右端点的r,对于同一块的询问,将>r的右端点逐渐增加向右扩展并累计。对于每次询问,暴力增加块内的部分,用栈记录修改然后清除。(体现了分块算法一贯的思想:块内暴力,块间转移)

复杂度O(n√m)。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=50010;
int a[maxn],ANS[maxn],s1[maxn*2],s2[maxn*2],up[maxn],down[maxn],top,ans,answer;
int n,m;
struct cyc{int l,r,q,id;}b[maxn];
bool cmp(cyc x,cyc y){return x.q^y.q?x.q<y.q:x.r<y.r;}
void modify(int x){
    up[x]=up[x+1]+1;
    down[x]=down[x-1]+1;
    int t=up[x]+down[x]-1;
    s1[++top]=x+up[x]-1;s2[top]=down[s1[top]];
    s1[++top]=x-down[x]+1;s2[top]=up[s1[top]];
    down[s1[top-1]]=up[s1[top]]=t;
    ans=max(ans,t);
}
int main(){
    scanf("%d%d",&n,&m);
    int Q=(int)(1.0*n/sqrt(m));
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=m;i++){scanf("%d%d",&b[i].l,&b[i].r);b[i].q=(b[i].l-1)/Q+1;b[i].id=i;}
    sort(b+1,b+m+1,cmp);
    int r=0,t=0;
    for(int i=1;i<=m;i++){
        if(b[i].q!=b[i-1].q){
            memset(up,0,sizeof(up));
            memset(down,0,sizeof(down));
            t=r=b[i].q*Q;answer=0;
        }
        ans=0;top=0;
        while(b[i].r>r)modify(a[++r]);
        top=0;//forget...
        answer=ans=max(answer,ans);
        for(int j=b[i].l;j<=min(t,b[i].r);j++)modify(a[j]);
        ANS[b[i].id]=ans;
        for(int j=top;j>=1;j--)if(j%2)down[s1[j]]=s2[j];else up[s1[j]]=s2[j];
        for(int j=b[i].l;j<=min(t,b[i].r);j++)up[a[j]]=down[a[j]]=0;
    }
    for(int i=1;i<=m;i++)printf("%d\n",ANS[i]);
    return 0;
}

注意:栈数组开2倍

还有想着后面要记得写的东西可以先写到草稿纸上,不然后面忘了……GG

原文地址:https://www.cnblogs.com/onioncyc/p/8569507.html

时间: 2024-11-06 16:14:46

【BZOJ】4358: permu 莫队算法的相关文章

BZOJ 3585 mex 莫队算法+分块

题目大意:给定一个长度为n的数组,m次询问某个区间内的mex值 怒写莫队233 将权值分成√n块,记录每个权值的出现次数以及每块内有多少权值出现过 修改O(1)即可完成 查询时首先扫一遍找到第一个块内有没有覆盖的点的块 然后在块内暴力查找 时间复杂度O(√n) 套个莫队 总时间复杂度O(m√n) #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include

BZOJ 3289:Mato的文件管理(莫队算法+树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=3289 题意:…… 思路:求交换次数即求逆序对数.确定了这个之后,先离散化数组.然后在后面插入元素的话,就是在区间里面找比它大的元素数量,在前面插入元素的话,就是在区间里面找比它小的元素数量.删除操作类似.因为排序是从小到大排序,所以要找比它大的数量就是区间长度减去小于等于该元素的数量,所以是(R - L + 1 - sum(a[i])),要找比它小的数量就是(sum(a[i] - 1)).然后用莫

BZOJ 1878 SDOI2009 HH的项链 树状数组/莫队算法

题目大意:给定一个序列.求一个区间内有多少个不同的数 正解是树状数组 将全部区间依照左端点排序 然后每次仅仅统计左端点開始的每种颜色的第一个数即可了 用树状数组维护 我写的是莫队算法 莫队明显能搞 m√m明显慢了点可是还是能接受的一个复杂度 一開始离散化数组开小了各种秒RE-- 跪了 #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algori

bzoj 2038 [2009国家集训队]小Z的袜子(hose) 莫队算法

2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 10239  Solved: 4659[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命--具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两

BZOJ 1878 [SDOI2009]HH的项链 (主席树 或 莫队算法)

题目链接  HH的项链 这道题可以直接上主席树的模板 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 5e4 + 10; const int M = 3e6 + 10

BZOJ 2038: [2009国家集训队]小Z的袜子(hose)【莫队算法裸题&amp;&amp;学习笔记】

2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 9894  Solved: 4561[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两

BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】

2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7687  Solved: 3516[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只

BZOJ 3236 AHOI 2013 作业 莫队算法

题目大意:给出一些数,问在一个区间中不同的数值有多少种,和在一个区间中不同的数值有多少个. 思路:由于没有修改,所以就想到了莫队算法.然后我写了5K+的曼哈顿距离最小生成树,然后果断T了.(100s的时限啊,刷status都要刷疯了..,结果最后加了手写读入也没能A).后来果断放弃,写了分块版的莫队算法.84sAC...这题卡的..貌似莫队并不是正解. 其实用分块来写莫队就很简单了.只需要将所有询问的区间排序,左端点所在块作为第一键值,右端点作为第二季键值排序,之后就可以转移了.理论上来时还是曼

BZOJ 2038 小Z的袜子(莫队算法)

莫队算法如果我们已知[l,r]的答案,能在O(1)时间得到[l+1,r]的答案以及[l,r-1]的答案,即可使用莫队算法.时间复杂度为O(n^1.5).如果只能在logn的时间移动区间,则时间复杂度是O(n^1.5*log n).其实就是找一个数据结构支持插入.删除时维护当前答案. 这道题的话我们很容易用数组来实现,做到O(1)的从[l,r]转移到[l,r+1]与[l+1,r]. 那么莫队算法怎么做呢?以下都是在转移为O(1)的基础下讨论的时间复杂度.另外由于n与m同阶,就统一写n.如果已知[l