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. 指标统计:基于流计算 Oceanus(Flink) 实现实时 UVPV 统计

    作者:吴云涛,腾讯 CSIG 高级工程师导语 | 最近梳理了一下如何用 Flink 来实现实时的 UV.PV 指标的统计,并和公司内微视部门的同事交流.然后针对该场景做了简化,并发现使用 Flink ...

  2. Sequence Model-week1编程题2-Character level language model【RNN生成恐龙名 LSTM生成莎士比亚风格文字】

    Character level language model - Dinosaurus land 为了构建字符级语言模型来生成新的名称,你的模型将学习不同的名字,并随机生成新的名字. 任务清单: 如何 ...

  3. 自动化键盘,python

    国际惯例先上源https://github.com/boppreh/keyboard#键盘输入 from pynput.keyboard import Key,Controller,Listener ...

  4. aritest发送测试报告到邮件

    #!/usr/bin/env python # -*- coding=utf-8 -*- __CreateAt__ = '2020/4/19-17:34' import shutil from air ...

  5. Beta实际开发与初始计划的比较

    零.说明 本篇博客为Beta阶段开始十天后,实际开发工作与初始计划的比较 截止至本篇博客发布为止,团队所有成员已完成计网考试,将在本周日进行充分的接口测试 一.比较 1.与初始计划对比 初始计划 实际 ...

  6. 关于麦克风的参数介绍 - 驻极体麦克风(ECM)和硅麦(MEMS)

    1.麦克风的分类1.1.动圈式麦克风(Dynamic Micphone)原理:基本构造包含线圈.振膜.永久磁铁三部分.当声波进入麦克风,振膜受到声波的压力而产生振动,与振膜在一起的线圈则开始在磁场中移 ...

  7. linux中的strip命令简介

    转载:https://blog.csdn.net/qq_37858386/article/details/78559490 strip:去除,剥去     一.下面是man strip获得到的信息,简 ...

  8. Spoj 2878 KNIGHTS - Knights of the Round Table | 双联通分量 二分图判定

    题目链接 考虑建立原图的补图,即如果两个骑士不互相憎恨,就在他们之间连一条无向边. 显而易见的是,如果若干个骑士在同一个点数为奇数的环上时,他们就可以在一起开会.换句话说,如果一个骑士被一个奇环包含, ...

  9. hdu 2201 熊猫阿波的故事(简单概率。。)

    题意: 阿波上了飞机,飞机上有座位1,2,....,N.第i个乘客本应坐在第i个座位上. 可是阿波随便找了个座位就坐了下来,接下来大家也都随便找了个座位坐了下来. 问:第i个乘客坐到原座位的概率是多少 ...

  10. Loto实践干货(8) 实测 保险丝 用示波器带电流探头

    本文用LOTO示波器和5A的电流探头来实验两种常见类型的保险丝的保护曲线.一种是熔断型的,另一种是自恢复型的.我们通常需要在一些电路中对电流过大的情况做保护,比如防止用户把输出源短路,比如防止用户对电 ...