bzoj4865: [Ynoi2017]由乃运椰子

在线询问区间众数,传统的分块(记录块间众数和每个权值的出现次数)做法被卡空间(分块用的空间是O(块数*(块数+权值种类数))),因此考虑去掉出现次数较小的数,只用分块维护出现次数较大的数。设K为分界线,用原来的分块维护原序列中出现次数>K的数组成的部分,而出现次数<=K的数,可以通过记录一个数前面第1~K个相同的数的位置,用线段树维护,线段树查询时利用单调性单次询问可以做到$O(k+logn)$,不会成为瓶颈。

当K取$O(n^{1/4})$时,时间复杂度仍是$O(q\sqrt{n})$,空间复杂度为$O(n^{5/4})$

#include<bits/stdc++.h>
char buf[65555],*ptr=buf+65536;
int g(){
    if(ptr-buf==65536)fread(buf,1,65536,stdin)[buf]=0,ptr=buf;
    return *ptr++;
}
int __(){
    int x=0,c=g();
    while(c<48)c=g();
    while(c>47)x=x*10+c-48,c=g();
    return x;
}
int _(){
    if(ptr-buf>65500)return __();
    int x=0,c=*ptr++;
    while(c<48)c=*ptr++;
    while(c>47)x=x*10+c-48,c=*ptr++;
    return x;
}
typedef unsigned short u16;
int n,m;
int v0[60007],vs[60007],B,v1[60007],vp1=0;
u16 bc[365][6677],ws[60007],t[60007],rid[60007],bb[365][365],pv[60007],pw[60007];
int ls[405],rs[405];
u16 tr[131111][7];
int max(int a,int b){return a>b?a:b;}
int get(int l,int r){
    int p=0;
    for(int a=l+65535,b=r+65537;b-a!=1&&p<7;a>>=1,b>>=1){
        if(~a&1)while(p<7&&tr[a^1][p]>=l)++p;
        if(b&1)while(p<7&&tr[b^1][p]>=l)++p;
    }
    return p+1;
}
int main(){
    n=_();m=_();
    for(int i=1;i<=n;++i)vs[i]=v0[i]=_();
    std::sort(vs+1,vs+n+1);
    for(int i=1;i<=n;++i)v0[i]=std::lower_bound(vs+1,vs+n+1,v0[i])-vs;
    for(int i=1;i<=n;++i){
        int x=v0[i];
        pv[i]=pw[x];
        pw[x]=i;
        for(int j=0,z=pv[i];j<7;++j)tr[i+65536][j]=z,z=pv[z];
    }
    for(int i=65535;i;--i){
        int a=i<<1,b=a^1;
        for(int j=0;j<7;++j)tr[i][j]=max(tr[a][j],tr[b][j]);
    }
    for(int i=1;i<=n;++i)++t[v0[i]];
    int idp=0;
    for(int i=1;i<=n;++i)if(t[i]>8)rid[i]=++idp;

    for(int i=1;i<=n;++i)if(rid[v0[i]]){
        v1[++vp1]=rid[v0[i]];
        v0[i]=vp1;
    }else v0[i]=v0[i-1];
    for(int i=1;i<=n;++i)t[i]=0;
    n=vp1;
    for(B=1;n/B>362;++B);
    for(int l=1,r=B,c=1;l<=n;l+=B,r+=B,++c){
        if(r>n)r=n;
        ls[c]=l;rs[c]=r;
        for(int i=ls[c];i<=rs[c];++i)ws[i]=c;
        for(int b=c;b;--b){
            bb[c][b]=bb[c][b+1];
            for(int i=ls[b];i<=rs[b];++i)if(v1[i]){
                int x=++bc[c][v1[i]];
                if(x>bc[c][bb[c][b]])bb[c][b]=v1[i];
            }
        }
    }
    int la=0;
    while(m--){
        int L=_()^la,R=_()^la;
        int a0=get(L,R);
        L=v0[L-1]+1;R=v0[R];
        int l=ws[L],r=ws[R];
        if(a0<8)la=a0;
        else if(r-l<=1){
            la=a0;
            for(int i=L;i<=R;++i){
                int x=v1[i];
                if(x&&++t[x]>la)la=t[x];
            }
            for(int i=L;i<=R;++i)--t[v1[i]];
        }else{
            --r,++l;
            int mx=bb[r][l];
            u16*s1=bc[r],*s2=bc[l-1];
            for(int i=rs[l-1];i>=L;--i){
                int x=v1[i];
                int t1=++t[x]+s1[x]-s2[x];
                if(t1>t[mx]+s1[mx]-s2[mx])mx=x;
            }
            for(int i=ls[r+1];i<=R;++i){
                int x=v1[i];
                int t1=++t[x]+s1[x]-s2[x];
                if(t1>t[mx]+s1[mx]-s2[mx])mx=x;
            }
            la=max(a0,t[mx]+bc[r][mx]-bc[l-1][mx]);
            for(int i=rs[l-1];i>=L;--i)--t[v1[i]];
            for(int i=ls[r+1];i<=R;++i)--t[v1[i]];
        }
        printf("-%d\n",la);
    }
    return 0;
}
时间: 2024-08-10 02:11:43

bzoj4865: [Ynoi2017]由乃运椰子的相关文章

BZOJ3597: [Scoi2014]方伯伯运椰子

输入格式: 第1 行包含2 个整数n,m接下来m 行代表m 条边,表示这个交通网络.每行6 个整数,表示ui,vi,ai,bi,ci,di.接下来1 行包含1 条边,表示连接起点的边 输出格式: 一个浮点数,保留2 位小数,表示要求的答案,数据保证答案大于0 样例输入: 6 7 1 2 0 0 1 1000 2 4 0 0 1 1000 4 6 0 0 1 1000 1 3 0 0 0 0 3 5 0 0 0 0 5 6 0 0 0 0 6 8 0 0 1 0 7 1 0 0 1 0 样例输出:

BZOJ3597 [Scoi2014]方伯伯运椰子 【二分 + 判负环】

题目链接 BZOJ3597 题解 orz一眼过去一点思路都没有 既然是流量网络,就要借鉴网络流的思想了 我们先处理一下那个比值,显然是一个分数规划,我们二分一个\(\lambda = \frac{X - Y}{k}\) 如果\(\lambda\)成立,则 \[\lambda \le \frac{X - Y}{k}\] 即 \[\lambda k + (Y - X) \le 0\] 所以我们只需要判断是否存在一种方案使得这个式子成立 依照网络流的思想,撤回流量就往反向边走,扩展流量往正向边 对于边

bzoj 3597 [Scoi2014] 方伯伯运椰子 - 费用流 - 二分答案

题目传送门 传送门 题目大意 给定一个费用流,每条边有一个初始流量$c_i$和单位流量费用$d_i$,增加一条边的1单位的流量需要花费$b_i$的代价而减少一条边的1单位的流量需要花费$a_i$的代价.要求最小化总费用减少量和调整次数的比值(至少调整一次). 根据基本套路,二分答案,移项,可以得到每条边的贡献. 设第$i$条边的流量变化量为$m_i$,每次变化花费的平均费用为$w_i$.那么有 $\sum c_id_i - \sum (c_i + m_i)d_i + |m_i|(w_i + mi

待 题表

题表 达哥终极杂题表Bzoj2839 hdu6021 Codeforces 804DBzoj2248 hdu5575 Codeforces 786CBzoj2013 bzoj2676 Codeforces 803CBzoj2386 bzoj3782 Codeforces 813DBzoj2699 cogs1667 Codeforces 814DBzoj4798 bzoj2064 Codeforces 814EBzoj4639 bzoj3505 Codeforces 815ABzoj4417 bz

YCB 的暑期计划

前言 YCB现在很弱(TAT) 暑假有一个月,赶快狂补一下. 大概的计划如下: 首先前期会以数据结构为主,毕竟代码能力太弱,涉及内容:线段树分治.二进制分组.KD-Tree. 等数据结构做到没有智商的时候加入一波数论,内容为 杜教筛.min_25筛. 然后中途小清新一下,做一些 组合博弈与构造题. 接着继续练代码能力,顺便学一些神奇的暴力:启发式合并.dsu on tree . 然后图论也忘的差不多了,就回过头去学点新东西,大概会有spfa判负环.0/1分数规划.差分约束. 估计这个时候也没有什

分数规划小结

https://www.zybuluo.com/ysner/note/1262173 定义 给定数列\(\{a\},\{b\}\),求解一组数列\(\{x\}\)(\(x_i=\{0,1\}\)) 使得\[\frac{\sum_{i=1}^na_i*x_i}{\sum_{i=1}^nb_i*x_i}\] 最大化. 方法 主要是二分答案. 设二分出的值为\(mid\), 则应有\[\frac{\sum_{i=1}^na_i*x_i}{\sum_{i=1}^nb_i*x_i}\geq mid\] 化

【CF802C】Heidi and Library

CF的C题就这么难,自闭了. 题面 https://www.luogu.org/problem/CF802C 题解 除了秒切的,费用流题大体上分成2种: 从点的角度思考:流量守恒列方程,把方程看做点,把变量看成边,典型的有志愿者招募.Delight for a Cat. 从流的角度思考:一个流代表一个过程,典型的有餐巾计划问题和最长k可重区间集问题. 模型: 分类模型:可以看做最小割的加强版,如序列48分做法. 调整模型:方伯伯运椰子.球队收益. 从流的角度思考的一道好题,同时也是我的第一道最小

Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)

如果没有用来读取注解的工具,那注解将基本没有任何作用,它也不会比注释更有用.读取注解的工具叫作注解处理器.Java提供了两种方式来处理注解:第一种是利用运行时反射机制:另一种是使用Java提供的API来处理编译期的注解. 反射机制方式的注解处理器 仅当定义的注解的@Retention为RUNTIME时,才能够通过运行时的反射机制来处理注解.下面结合例子来说明这种方式的处理方法. Java中的反射API(如java.lang.Class.java.lang.reflect.Field等)都实现了接

51CTO持续更新《通哥的运维笔记》

<通哥的运维笔记>将持续在51CTO网站更新,希望大家多多关注.互相学习,后期,我将会退出<通哥的运维笔记>系列视频教程,希望带给大家最大的收获,帮助大家更好的学习.进步.<通哥的运维笔记>主要从linux系统管理.虚拟化.cloudstack云平台以及网络管理之CCNA.CCNP.CCIE,等等方面深入讲解.