Codeforces 题目传送门 & 洛谷题目传送门

首先考虑 \(p>50\) 的时候怎么处理,也就是求一个区间的绝对众数。我们知道众数这个东西是不能用线段树直接维护的,因为对于区间 \([l,r]\) 和 \(x\in [l,r)\),区间 \([l,r]\) 的众数不一定是 \([l,x]\) 的众数或 \([x+1,r]\) 的众数。

不过此题有一个特殊之处,就是我们要求区间的绝对众数而不是区间的众数。这时候就可以用线段树维护了,因为区间 \([l,r]\) 的绝对众数一定至少是区间 \([l,x],[x+1,r]\) 中某个区间的绝对众数(提示:反证法)。

于是我们考虑这样一个思路,对于 \([l,r]\) 中的所有数组成一个可重集 \(S\),每次选择两个数 \(x,y\in S\) 且 \(x\ne y\) 并将 \(x,y\) 从 \(S\) 中删除,直到 \(S=\varnothing\) 或 \(S\) 中所有数都相同为止。不难发现在任意时刻,原区间中的绝对众数还是 \(S\) 中的绝对众数,因为对于 \([l,r]\) 中的绝对众数 \(z\),我们设其出现次数为 \(c\),若删去的两数满足 \(x\ne z\land y\ne z\),那么删去 \(x,y\) 后还剩 \(n-2\) 个数,其中 \(z\) 出现的次数为 \(c\),\(c>\lfloor\dfrac{n}{2}\rfloor>\lfloor\dfrac{n-2}{2}\rfloor\);若删去的两数满足 \(x=z\lor y=z\),那么删去 \(x,y\) 后 \(z\) 出现的次数为 \(c-1\),由 \(c>\lfloor\dfrac{n}{2}\rfloor\) 知 \(c-1>\lfloor\dfrac{n-2}{2}\rfloor\)。我们建一棵线段树,区间 \([l,r]\) 表示的节点上维护两个值 \(x,y\),\(x\) 为将 \([l,r]\) 中所有数压入 \(S\) 后对 \(S\) 进行上文所说的操作后 \(S\) 中剩余的数,如果最终 \(S=\varnothing\) 则该值为 \(0\),\(y\) 是删完后 \(x\) 的出现次数,合并两个区间 \([l,r]\) 时就将两个子区间的 \(y\) 值作比较,并令当前区间的 \(x\) 为两个子区间的 \(y\) 值较大的 \(x\),\(y\) 值为两个子区间的 \(y\) 值相减即可。

到这里你可能会有疑惑,那就是任意时刻 \(x\) 为 \(S\) 中的绝对众数并不是 \(x\) 为原区间的绝对众数的充要条件,它仅仅只是必要条件。也就是说有可能出现最终留下的数不是原区间的绝对众数。但是注意到题目中有个奇奇怪怪的条件,叫做“输出的数中可以包含错误的数,但正确的数必须包含在输出中,并且输出的数不能超过 \(\lfloor\dfrac{100}{p}\rfloor\)”,在上述算法中我们最多输出一个数,并且可以保证若 \([l,r]\) 存在绝对众数,那么其绝对众数一定被输出,故这样是符合题意。

接下来考虑原题。我们记 \(k=\lfloor\dfrac{100}{p}\rfloor\)。由于 \(p\geq 20\),一定有 \(k\leq 5\),也就是说我们最多输出 \(5\) 个数。我们还是考虑之前的算法,只不过把“每次删除 \(2\) 个数”改为“每次删除 \(k+1\) 个数”,然后用一个 std::vector<pair<int,int> > 维护该区间中的数执行上述操作后剩余的数,以及它们的出现次数。合并时候就暴力合并左右子区间的 vector,取出现次数最大的 \(k\) 个数即可。借鉴上面的分析可知输出的数仍可能包含错误的数,但正确的数一定被包含在答案中。

时间复杂度 \(nk^2\log n\),其中 \(k_{\max}=5\)

不过似乎 std::vector<pair<int,int> > 常数有亿点点大?或许是 wtcl 罢,用 std::vector<pair<int,int> > 实现的代码 TLE 50 了,故这里是用结构体实现的代码:

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1.5e5;
const int INF=0x3f3f3f3f;
int n,qu,p,a[MAXN+5];
struct seq{
int cnt,x[8],y[8];
seq(){cnt=0;fill0(x);fill0(y);}
};
struct node{int l,r,lz;seq v;} s[MAXN*4+5];
seq merge(seq a,seq b){
for(int i=1;i<=b.cnt;i++){
bool ok=0;
for(int j=1;j<=a.cnt;j++){
if(a.x[j]==b.x[i]){
a.y[j]+=b.y[i];
ok=1;break;
}
} if(ok) continue;
a.x[++a.cnt]=b.x[i];a.y[a.cnt]=b.y[i];int mn=INF;
if(a.cnt<=p) continue;
for(int j=1;j<=a.cnt;j++) chkmin(mn,a.y[j]);
seq c;
for(int j=1;j<=a.cnt;j++) if(a.y[j]-mn)
c.x[++c.cnt]=a.x[j],c.y[c.cnt]=a.y[j]-mn;
a=c;
} return a;
}
void pushup(int k){s[k].v=merge(s[k<<1].v,s[k<<1|1].v);}
void build(int k=1,int l=1,int r=n){
s[k].l=l;s[k].r=r;if(l==r){s[k].v.cnt=1;s[k].v.x[1]=a[l];s[k].v.y[1]=1;return;}
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}
void pushdown(int k){
if(s[k].lz){
s[k<<1].v.cnt=1;s[k<<1].v.x[1]=s[k].lz;
s[k<<1].v.y[1]=s[k<<1].r-s[k<<1].l+1;
s[k<<1].lz=s[k].lz;
s[k<<1|1].v.cnt=1;s[k<<1|1].v.x[1]=s[k].lz;
s[k<<1|1].v.y[1]=s[k<<1|1].r-s[k<<1|1].l+1;
s[k<<1|1].lz=s[k].lz;
s[k].lz=0;
}
}
void modify(int k,int l,int r,int x){
if(l<=s[k].l&&s[k].r<=r){
s[k].v.cnt=1;s[k].v.x[1]=x;
s[k].v.y[1]=s[k].r-s[k].l+1;
s[k].lz=x;return;
} pushdown(k);int mid=s[k].l+s[k].r>>1;
if(r<=mid) modify(k<<1,l,r,x);
else if(l>mid) modify(k<<1|1,l,r,x);
else modify(k<<1,l,mid,x),modify(k<<1|1,mid+1,r,x);
pushup(k);
}
seq query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r) return s[k].v;
int mid=s[k].l+s[k].r>>1;pushdown(k);
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return merge(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
}
int main(){
scanf("%d%d%d",&n,&qu,&p);p=100/p;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);build();
while(qu--){
int opt;scanf("%d",&opt);
if(opt==1){int l,r,x;scanf("%d%d%d",&l,&r,&x);modify(1,l,r,x);}
else{
int l,r;scanf("%d%d",&l,&r);seq ret=query(1,l,r);
printf("%d ",ret.cnt);for(int i=1;i<=ret.cnt;i++) printf("%d ",ret.x[i]);
printf("\n");
}
}
return 0;
}

Codeforces 643G - Choosing Ads(线段树)的更多相关文章

  1. Buses and People CodeForces 160E 三维偏序+线段树

    Buses and People CodeForces 160E 三维偏序+线段树 题意 给定 N 个三元组 (a,b,c),现有 M 个询问,每个询问给定一个三元组 (a',b',c'),求满足 a ...

  2. CodeForces 877E DFS序+线段树

    CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...

  3. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  4. [Codeforces 1199D]Welfare State(线段树)

    [Codeforces 1199D]Welfare State(线段树) 题面 给出一个长度为n的序列,有q次操作,操作有2种 1.单点修改,把\(a_x\)修改成y 2.区间修改,把序列中值< ...

  5. [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)

    [Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...

  6. Codeforces Gym 100231B Intervals 线段树+二分+贪心

    Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...

  7. Codeforces 482B Interesting Array(线段树)

    题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,如今有M个限制,每一个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 ...

  8. codeforces 383C Propagating tree 线段树

    http://codeforces.com/problemset/problem/383/C 题目就是说,  给一棵树,将一个节点的值+val, 那么它的子节点都会-val, 子节点的子节点+val. ...

  9. CodeForces 228D. Zigzag(线段树暴力)

    D. Zigzag time limit per test 3 seconds memory limit per test 256 megabytes input standard input out ...

随机推荐

  1. 4.1 The Example Domain 领域示例代码

    4.1 The Example Domain 领域示例代码 The examples will use some concepts those are used by GitHub, like Iss ...

  2. Java:反射小记

    Java:反射小记 对 Java 中的 反射,做一个微不足道的小小小小记 概念 Java 反射指的是在 Java 程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法:对于给定的一个对象, ...

  3. TortoiseGit使用

    TortoiseGit 前言: 其实作为一名学生,还未接触过企业级开发项目,基本都是一个人在本地敲代码,对于项目管理工具使用的并不多,最常用的命令也就是git clone了,hhh: 前些日子了解了一 ...

  4. 使用registry搭建docker私服仓库

    使用registry搭建docker私服仓库 一.拉取 registry镜像 二.根据镜像启动一个容器 1.创建一个数据卷 2.启动容器 三.随机访问一个私服的接口,看是否可以返回数据 四.推送一个镜 ...

  5. netty入门实现简单的echo程序

    最近看以往在程序中编写的代码,发现有一个功能是使用socket通讯来实现的,而那个时候使用的是基于bio的阻塞io来实现的,最近在看netty,发现可以使用netty来使用nio的方式来实现,此博客记 ...

  6. Balance的数学思想构造辅助函数

    本类题的证明难点便在于如何构造出满足答案的辅助函数.通过下列类题便可以很好的理解. 题一 该类题可以理解为积分内部f(x)与xf(x)处于一种失衡状态,故我们需要使其平衡,否则直接构造出的函数无法满足 ...

  7. 从0到1使用Kubernetes系列(五):Kubernetes Scheduling

    前述文章介绍了Kubernetes基本介绍,搭建Kubernetes集群所需要的工具,如何安装,如何搭建应用.本篇介绍怎么使用Kubernetes进行资源调度. Kubernetes作为一个容器编排调 ...

  8. linux中的分号 && ||

    几个符号的用法 ; 顺序地独立执行各条命令, 彼此之间不关心是否失败, 所有命令都会执行. && 顺序执行各条命令, 只有当前一个执行成功时候, 才执行后面的. & 放在启动参 ...

  9. 集合栈 牛客网 程序员面试金典 C++ Python

    集合栈 牛客网 程序员面试金典 C++ Python 题目描述 请实现一种数据结构SetOfStacks,由多个栈组成,其中每个栈的大小为size,当前一个栈填满时,新建一个栈.该数据结构应支持与普通 ...

  10. Android WebView 实现文件选择、拍照、录制视频、录音

    原文地址:Android WebView 实现文件选择.拍照.录制视频.录音 | Stars-One的杂货小窝 Android中的WebView如果不进行相应的设置,H5页面的上传按钮是无法触发And ...