Choosing Ads

问题提出

  • 给出长度为nnn的序列AAA,以及数ppp(20≤p≤10020\le p \le 10020≤p≤100)
  • QQQ次操作,两种类型
    • (1,l,r)(1,l,r)(1,l,r),区间赋值为vvv
    • (2,l,r)(2,l,r)(2,l,r),区间出现频率≥p%\ge p\%≥p%的数
  • n,Q≤105n,Q \le 10^5n,Q≤105

问题解答

非常巧妙的一道题,用到了主元素的思想.

我们先考虑一个简单的问题,如何在一个序列中找主元素(出现频次>50%\gt 50\%>50%的元素),要求O(n)O(n)O(n)的时间复杂度和O(1)O(1)O(1)的空间复杂度.

这是一个很经典的问题,我们用到的思想就是分组,主元素一组,其他元素一组,然后各组之间每次同时抵消掉111个元素,那么最后剩下的一组一定是主元素.

编程实现如下:

//算法1
int rec = a[0],cnt = 1;
for(int i = 1;i < n;++i) {if(a[i] == rec) ++cnt;else if(--cnt == 0) rec = a[i],cnt = 1;
}

如果有主元素的话,最后recrecrec表示的一定是主元素.我们把变量nnn叫做主元素recrecrec的平衡度.对于任一序列AAA,可以证明最坏情况下主元素的平衡度都至少为111.

我们再考虑一个问题.

将分别求出序列A,BA,BA,B的主元素recArec_ArecA​和recBrec_BrecB​,以及它们的平衡度cntAcnt_AcntA​和cntBcnt_BcntB​.

将A,BA,BA,B拼成一个新的序列,那么主元素也一定是recArec_ArecA​和recBrec_BrecB​中的其中一个.这是很显然的,证明略去.

现在我们要判定主元素到底是recArec_ArecA​还是recBrec_BrecB​,我们只需要将他们相互抵消即可,换句话说看谁的cntcntcnt大,谁就是.

你可以理解为这就相当于直接在ABABAB序列上跑算法1算法1算法1,只不过序列的顺序有所改变.

这样的话,我们有了222个子序列的主元素以及平衡度,我们就可以得到该序列的主元素以及平衡度.

假设cntA&gt;cntBcnt_A &gt; cnt_BcntA​>cntB​主元素就是recAB=recArec_{AB} = rec_ArecAB​=recA​,平衡度就是cntAB=cntA−cntBcnt_{AB}=cnt_A-cnt_BcntAB​=cntA​−cntB​

这样我们就可以得到一个分治的算法,即算法2.

至此,基础知识就说完了,我们回到这道题中.

这道题要求的是≥p%\ge p\%≥p%的是一定要输出,因此主元素有好多个至多k=⌊100p⌋k = \lfloor \frac{100}{p} \rfloork=⌊p100​⌋个.

我们可以根据一个序列的有kkk个主元素分为k+1k+1k+1组,其中每个主元素自己一组,然后其他元素一组.

用kkk个变量记录该序列的kkk个主元素,用kkk个变量记录每个元素的平衡度,每遇到一个元素,判断kkk个位置中有没有出现过,出现过就该位置平衡度+1,否则判断有没有空位,有的话就作为一个新的主元素,平衡度设置为1.再否则的话就令所有kkk个位置的平衡度-1(相当于抵消操作),如果平衡度为0就将这个元素拿走.

刚才说的是线性扫的做法,这道题要用线段树维护,就要该进程类似算法2的做法.

这道题用平衡树来维护上述信息,然后用算法2的精髓来实现线段合并操作.

代码

By csfxjtu96, contest: VK Cup 2016 - Round 3, problem: (G) Choosing Ads, Accepted, ##include <iostream>
#include <unordered_map>
#include <cstring>
#include <algorithm>#define pr(x) std::cout << #x <<" : " << x << std::endl
#define rep(i,a,b) for(int i = a;i <= b;++i)
#define clr(x) memset(x,0,sizeof(x))typedef std::pair<int,int> pii;const int N = 150001;
struct node {int len;pii ps[5];node(){len = 0;clr(ps);}
}seg[N<<2];int tag[N<<2];
int num[N];
int n,m,p,L;pii ps[10];
int mp[N],vis[N];
inline node maintain(node &lch,node &rch) {node res = node();res.len = lch.len + rch.len;rep(i,0,L-1) {mp[lch.ps[i].first] += lch.ps[i].second;mp[rch.ps[i].first] += rch.ps[i].second;}int pc = 0;memset(ps,0,sizeof(ps));rep(i,0,L-1) {if(!vis[lch.ps[i].first]) {ps[pc++] = (pii){lch.ps[i].first,mp[lch.ps[i].first]};vis[lch.ps[i].first] = 1;}if(!vis[rch.ps[i].first]) {ps[pc++] = (pii){rch.ps[i].first,mp[rch.ps[i].first]};vis[rch.ps[i].first] = 1;}}rep(i,0,L-1) {vis[rch.ps[i].first] = vis[lch.ps[i].first] = mp[lch.ps[i].first] = mp[rch.ps[i].first] = 0;}std::sort(ps,ps+pc,[](pii &p1,pii &p2){return p1.second > p2.second;});int cc = ps[L].second;rep(i,0,L-1) {ps[i].second -= cc;res.ps[i] = ps[i];}return res;
}inline void pushdown(int o) {if(tag[o]) {tag[o<<1] = tag[o<<1|1] = tag[o];clr(seg[o<<1].ps);clr(seg[o<<1|1].ps);seg[o<<1].ps[0] = std::make_pair(tag[o],seg[o<<1].len);seg[o<<1|1].ps[0] = std::make_pair(tag[o],seg[o<<1|1].len);tag[o] = 0;}
}inline void change(int o,int l,int r,int cl,int cr,int val) {if(cl <= l && r <= cr) {tag[o] = val;clr(seg[o].ps);seg[o].ps[0] = (pii){val,r-l+1};return ;}if(r < cl || cr < l) return ;int mid = (l + r) >> 1;pushdown(o);change(o<<1,l,mid,cl,cr,val);change(o<<1|1,mid+1,r,cl,cr,val);seg[o] = maintain(seg[o<<1],seg[o<<1|1]);
}inline node query(int o,int l,int r,int ql,int qr) {if(ql <= l && r <= qr)return seg[o];if(r < ql || qr < l) return node();int mid = (l + r) >> 1;pushdown(o);node lch = query(o<<1,l,mid,ql,qr);node rch = query(o<<1|1,mid+1,r,ql,qr);node res = maintain(lch,rch);return res;
}inline void build(int o,int l,int r) {if(l == r) {seg[o] = node();seg[o].len = 1;seg[o].ps[0] = (pii){num[l],1};return ;}int mid = (l + r) >> 1;build(o<<1,l,mid);build(o<<1|1,mid+1,r);seg[o] = maintain(seg[o<<1],seg[o<<1|1]);
}int main() {std::ios::sync_with_stdio(false);std::cin >> n >> m >> p;L = 100 / p;rep(i,1,n) std::cin >> num[i];build(1,1,n);while(m--) {int tp,l,r,x;std::cin >> tp;if(tp == 1) {std::cin >> l >> r >> x;change(1,1,n,l,r,x);}else if(tp == 2) {std::cin >> l >> r;node res = query(1,1,n,l,r);int cnt = 0;rep(i,0,L-1) {if(res.ps[i].second) cnt++;}std::cout << cnt;rep(i,0,L-1) {if(res.ps[i].second) std::cout << " " << res.ps[i].first;}std::cout << std::endl;}}return 0;
}

线段树-Chossing Ads-分治,主元素思想,神题相关推荐

  1. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  2. [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 629  Solved: 371 [Submit][Stat ...

  3. 线段树(假)练习题一(学校OJ的题)

    Description 桌子上零散地放着若干个盒子,桌子的后方是一堵墙.如右图所示.现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上.问影子的总宽度是多少? Sample Input 20 ...

  4. 数据结构---线段树

    线段树 转载请注明出处,谢谢!http://blog.csdn.net/metalseed/article/details/8039326  持续更新中···   一:线段树基本概念 1:概述 线段树 ...

  5. CodeForces - 1311F Moving Points(线段树+离散化)

    题目链接:点击查看 题目大意:给出 x 轴上的 n 个点,每个点都有一个位置和一个速度,每个点会根据速度在 x 轴上移动,现在规定dis( x , y )为点 x 和点 y 在移动过程中的最小距离,我 ...

  6. 杭电1166敌兵布阵(线段树)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  7. CF1004F Sonya and Bitwise OR(线段树平衡复杂度+or 前缀性质)

    CF1004F Sonya and Bitwise OR 有一个长度为 \(n\) 的数组 \(\{a\}\),有 \(m\) 次操作,又给定一个数 \(x\),有两类操作: 1 i y 将 \(a_ ...

  8. 斜率优化之凸包优化与李超线段树

    文章目录 前言 凸包优化 第一步 第二步 最后一步 例一 转移方程 凸包优化 代码 例二 题目大意 转移方程 凸包优化 代码 李超线段树 思想 插入 查询 代码 例三 代码 例四 转移方程 怎么做 代 ...

  9. 敌兵布阵 线段树

    敌兵布阵 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description Li ...

最新文章

  1. leetcode算法题--环形链表
  2. 如何使用SAP云平台的Notification服务给Android应用推送通知消息
  3. 重新命名的linux命令,Linux 重命名命令自制详细介绍
  4. 代码换肤术——C#和VB(摘抄)
  5. 从程序员到项目经理(7):程序员加油站 -- 完美主义也是一种错
  6. (附源码)计算机毕业设计SSM基于图书管理系统
  7. 计算机上网记录怎么清除,如何清除上网记录?
  8. 针对芯片测试行业,常见stil,vcd,wgl,文件的转化,到93K,chroma,小总结
  9. ADODB.Stream 错误 #x27;800a0bb9#x27; 参数类型不正确,或不在可以接受的范围之内,或与其他参数冲突。
  10. java虚拟机开源_IBM J9 Java虚拟机正式开源
  11. 2021-2027全球与中国超声波焊接头市场现状及未来发展趋势
  12. win10电脑禁用开机自启动软件
  13. 微服务架构,springcloud核心组件和实战,docker容器
  14. 【武忠祥高等数学基础课笔记】反常积分
  15. IPv6 三个访问本地地址的小Tips
  16. Java实现导出Excel
  17. 黑客与画家:Milvus x Cleveland Museum of Art
  18. 迟重瑞果然嫁给了爱情,陈丽华不惜花费重金,安排师徒四人聚会
  19. 手机联系人不见了怎么恢复?简单的恢复方法
  20. WinForm(C#)应用程序之(破)脱壳和修改

热门文章

  1. 孕妇可以在计算机教室待吗,电脑对孕妇有辐射吗?孕妇使用电脑的注意事项
  2. 递归函数斐波那契数列python_使用Python函数递归实现斐波那契数列时为什么运行速度很慢?...
  3. Java并发之volatile
  4. [MyBatisPlus]常用注解_@TableName_@TableId_@TableField_@TableLogic通过全局配置配置主键生成策略
  5. P3899 [湖南集训]谈笑风生(线段树合并)
  6. Codeforces Round #613 (Div. 2) E. Delete a Segment 离散化
  7. Codeforces Round #701 (Div. 2) C. Floor and Mod 数学分块
  8. 【CF1189D】Add on a Tree【结论】【构造】
  9. 2020牛客暑期多校训练营(第一场)
  10. Loj#3130-「COCI 2018.12」Praktični【线性基】