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. STM32中操作寄存器GPIOB_CRL &= ~( 0x0F<< (4*0))与GPIOB_CRL &=~(0x0F)之间有什么区别吗?

    没有区别,作用相同.只是这样写便于修改和沿用. 对于只用到PB0端口的程序~(0x0f << (4*0)) 和~0x0f没有区别.0x0f <<(4*N) 就是 向左 移动N个 ...

  2. Android系统编程入门系列之应用权限的定义与申请

    在之前关于应用内数据本地保存为文件时,曾提到应用需要申请外部存储设备的读写权限才能访问外部存储中的文件.那么针对某一种权限,应用程序具体应该怎么申请使用呢?本文将详细介绍. 应用中的权限主要分为两类, ...

  3. 【数据结构与算法Python版学习笔记】目录索引

    引言 算法分析 基本数据结构 概览 栈 stack 队列 Queue 双端队列 Deque 列表 List,链表实现 递归(Recursion) 定义及应用:分形树.谢尔宾斯基三角.汉诺塔.迷宫 优化 ...

  4. [no_code][Beta]事后分析

    设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们要解决的目前的手写表单的电子化问题,办公电子化问题的一个key问题.定义十分清楚: 输入: 手写表单 ...

  5. [对对子队]会议记录5.16(Scrum Meeting3)

    今天已完成的工作 何瑞 ​ 工作内容:搭建关卡5.6,优化之前的成本系统 ​ 相关issue:搭建关卡4.5.6 ​ 相关签入:feat: 第五第六关搭建完成 吴昭邦 ​ 工作内容:搭建关卡5.6 ​ ...

  6. 【做题记录】 [HEOI2013]SAO

    P4099 [HEOI2013]SAO 类型:树形 \(\text{DP}\) 这里主要补充一下 \(O(n^3)\) 的 \(\text{DP}\) 优化的过程,基础转移方程推导可以参考其他巨佬的博 ...

  7. 助你上手Vue3全家桶之VueX4教程

    目录 1,前言 2,State 2.1,直接使用 2.2,结合computed 3,Getter 3.1,直接使用 3.2,结合computed 4,Mutation 4.1,直接使用 4.2,结合c ...

  8. hdu 1160 FatMouse's Speed(最长不下降子序列+输出路径)

    题意: FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to ...

  9. java 垃圾回收及内存分配策略

    一.在垃圾收集器对堆进行回收前,首先需要判断对象是否"存活",对已经"死去"的对象进行回收 判断对象是否存活:引用计数法和可达性分析法 引用计数法:给对象添加一 ...

  10. Mysql教程:(二)分组与函数查询group by

    分组与函数查询 温馨提示:分组之后查询其他函数结果是不正确的: 分组函数:group by 按班级分组,查询出每班数学最高分:select class,max(maths) from score gr ...