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

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

题意:给出一个长为 n的数列,以及 n个操作,操作涉及询问区间的最小众数。

思路:虽然这不是一道 回滚莫队题,就是 暴力分块 的题, 但是 还是 可以用回滚莫队 写滴,好像大部分题解都是 暴力分块。

#include<bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define dep(i,j,k) for(int i=k;i>=j;i--)
#define INF 0x3f3f3f3f
#define mem(i,j) memset(i,0,sizeof(i))
#define make(i,j) make_pair(i,j)
#define pb push_back
using namespace std;
const int N=1e5+111;
int a[N],b[N],c[N],cnt[N],pos[N],n,block;
int tmp,ans[N],coun;
struct noq {
    int l,r,id;
}q[N];
bool cmp(noq a,noq b) {
    return pos[a.l]==pos[b.l]?a.r<b.r:pos[a.l]<pos[b.l];
}
int query(int l,int r) { ///暴力求答案
    int t[N]; rep(i,l,r) t[b[i]]=0; int w=0,ww=0;
    rep(i,l,r) {
        ++t[b[i]];
        if(t[b[i]]>=ww) {
            if(t[b[i]]==ww && a[i]<w) w=a[i];
            else if(t[b[i]]>ww) ww=t[b[i]],w=a[i];
        }
    }
    return w;
}
void add(int x) {
    ++cnt[b[x]];
    if(cnt[b[x]]>=coun) {
            if(cnt[b[x]]==coun && a[x]<tmp) tmp=a[x];
            else if(cnt[b[x]]>coun) coun=cnt[b[x]],tmp=a[x];
        }
}
int slove(int qnum,int bnum) { ///处理 第 bnum 块, 现在 处理到 q[qnum] 这个查询
    int i=qnum; int L=min(bnum*block,n); int l=L+1,r=L; tmp=0; coun=0; ///L 即为块尾
    rep(j,1,n) cnt[j]=0; ///初始化,每处理一个块 都要 搞一次的啦
    for(;pos[q[i].l]==bnum;i++) {
        if(pos[q[i].l]==pos[q[i].r]) {/// l,r 在同一块,暴力处理
            ans[q[i].id]=query(q[i].l,q[i].r); continue;
        }
        while(r<q[i].r) add(++r); ///先移动 r 指针
        int w=tmp,ww=coun; ///记录 l 指针 移动前的 tmp 和 coun 值
        while(l>q[i].l) add(--l);
        ans[q[i].id]=tmp; ///记录答案
        tmp=w; coun=ww; ///还原 tmp 和 coun
        while(l<L+1) --cnt[b[l++]]; /// l 滚回块尾+1
    }
    return i; ///处理完这一块后,处理到第i个查询
}
int main() {
    scanf("%d",&n);
    block=sqrt(n);
    rep(i,1,n) {
        scanf("%d",&a[i]); c[i]=a[i]; pos[i]=(i-1)/block+1;///一定要加1喔,因为slove的时候l,r初始化需要
    }
    int up=pos[n]; ///块数
    sort(c+1,c+1+n);
    int newn=unique(c+1,c+1+n)-(c+1);
    rep(i,1,n) {
        b[i]=lower_bound(c+1,c+1+newn,a[i])-c;///数据太大,离散化a[i]
    }
    rep(i,1,n) {
        scanf("%d %d",&q[i].l,&q[i].r); q[i].id=i;
    }
    sort(q+1,q+1+n,cmp);
    int pp=1; ///处理到的 q[i],pp即为i;
    rep(i,1,up) {
        pp=slove(pp,i);
    }
    rep(i,1,n) printf("%d\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/Willems/p/10891635.html

时间: 2024-10-07 12:44:05

loj#6285 数列分块入门 9 ( 回 滚 )的相关文章

Loj 6285. 数列分块入门 9

链接: https://loj.ac/problem/6285 思路: 离散化处理下就好了,具体解释在代码里. ps: 小新新别看了,你学不会的 实现代码: #include<bits/stdc++.h> using namespace std; const int M = 1e5 + 10; int n,block,idx,a[M],bl[M],f[510][510],val[M],cnt[M]; vector<int>ve[M]; void pre(int x){ //预处理

LOJ#6284. 数列分块入门 8

#6284. 数列分块入门 8 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论 1 测试数据 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间询问等于一个数 ccc 的元素,并将这个区间的所有元素改为 ccc. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 i 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入三个数字 ll

LOJ6277~6285 数列分块入门

Portals 分块需注意的问题 数组大小应为\(N+\sqrt N\),因为最后一个块可能会超出\(N\)的范围.改成记录\(blk,fr,to\)就不用担心这个了 当操作的区间在一个块内时,要特判成暴力修改. 要清楚什么时候应该+tag[t] 最后一个块是越界的,注意是否有影响 数列分块入门 1 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间加法,单点查值. //数列分块入门 1 #include <cstdio> #include <cmath> inlin

Loj 6279. 数列分块入门 3

题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间加法,询问区间内小于某个值 xxx 的前驱(比其小的最大元素). 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 iii 个数字为 aia_iai?,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,以空格隔开. 若 opt=0\mathrm{opt} = 0opt=0,表示将位于 [l,r][l, r][l,r] 的之间的数字

Loj 6277 数列分块入门 1

题目链接:https://loj.ac/problem/6277 题面: 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间加法,单点查值. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 iii 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,以空格隔开. 若 opt=0\mathrm{opt} = 0opt=0,表示将位于 [l,r][l,

LibreOJ 6285. 数列分块入门 9

题目链接:https://loj.ac/problem/6285 其实一看到是离线,我就想用莫队算法来做,对所有询问进行分块,但是左右边界移动的时候,不会同时更新数字最多的数,只是后面线性的扫了一遍,所以还有百分之12的样例过不了. 然后看了别人分块,是先对所有零散的数字编号(这个应该是所谓离散化),用vector[i]存储编号为i的数字所有出现的位置,因为从0到n,所以里面的值是升序的,我们先对块与块之间数字最多的数进行计算(预处理),在查询的时候查询[l,r]之间的数,把区间分成三块,左边不

LOJ#6278. 数列分块入门 2

内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论测试数据 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间加法,询问区间内小于某个值 xxx 的元素个数. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 i 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,

LOJ#6281. 数列分块入门 5

内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论 1 测试数据 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间开方,区间求和. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 i 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,以空格隔开. 若 opt=

LOJ#6282. 数列分块入门 6

内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论测试数据 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及单点插入,单点询问,数据随机生成. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 i 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,以空格隔开. 若