HDU 4747 Mex【线段树上二分+扫描线】

【题意概述】
一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和。
【题解】
扫描线+线段树。
我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到右Mex单调上升。
然后我们把区间左端点逐渐向右边移动,也就是扫描线是左端点。
我们可以发现每次移动的影响就是 [这个数的位置, 这个数下一次出现的位置) 这个区间内大于这个数的Mex全部变为这个数。
那么我们在线段树上二分出第一个大于等于Mex的位置,然后区间修改即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define rg register
#define N 200010
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((a[u].l+a[u].r)>>1)
using namespace std;
int n,m,v[N],b[N],c[N],nxt[N],pos[N],mex[N];
LL ans,u[N];
struct tree{int l,r,nl,nr; LL sum; bool tag;}a[N<<];
inline int read(){
int k=,f=; char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(''<=c&&c<='')k=k*+c-'',c=getchar();
return k*f;
}
void build(int u,int l,int r){
a[u].l=l; a[u].r=r; a[u].tag=;
if(l<r){
build(ls,l,mid); build(rs,mid+,r);
a[u].sum=a[ls].sum+a[rs].sum; a[u].nl=a[ls].nl,a[u].nr=a[rs].nr;
}
else a[u].sum=a[u].nl=a[u].nr=mex[l];
}
inline void pushdown(int u){
a[ls].tag=a[rs].tag=;
a[ls].nl=a[ls].nr=a[rs].nl=a[rs].nr=a[u].nl;
a[ls].sum=(a[ls].r-a[ls].l+)*a[ls].nl;
a[rs].sum=(a[rs].r-a[rs].l+)*a[rs].nl;
a[u].tag=;
}
void update(int u,int l,int r,int num){
if(l<=a[u].l&&a[u].r<=r&&a[u].nl>num){
a[u].tag=; a[u].nl=a[u].nr=num; a[u].sum=(a[u].r-a[u].l+)*num;
return;
}
if(a[u].nr<=num) return;
if(a[u].tag) pushdown(u);
if(a[ls].nr>num&&l<=mid) update(ls,l,r,num);
if(r>mid) update(rs,l,r,num);
a[u].sum=a[ls].sum+a[rs].sum; a[u].nl=a[ls].nl,a[u].nr=a[rs].nr;
}
LL query(int u,int l,int r){
if(l<=a[u].l&&a[u].r<=r) return a[u].sum;
if(a[u].tag) pushdown(u); LL ret=;
if(l<=mid) ret+=query(ls,l,r);
if(r>mid) ret+=query(rs,l,r);
return ret;
}
inline void Pre(){
ans=;
memset(pos,,sizeof(pos));
memset(u,,sizeof(u));
}
int main(){
while(){
n=read(); if(!n) break;
Pre();
for(rg int i=;i<=n;i++) v[i]=b[i]=read();
sort(b+,b++n); m=unique(b+,b++n)-b-;
for(rg int i=;i<=n;i++) c[i]=lower_bound(b+,b++m,v[i])-b;
// for(rg int i=1;i<=n;i++) printf("%d ",c[i]); puts("c");
for(rg int i=n;i;i--) nxt[i]=(pos[c[i]])?pos[c[i]]:n+,pos[c[i]]=i;
// for(rg int i=1;i<=n;i++) printf("%d ",nxt[i]); puts("");
int now=;
for(rg int i=;i<=n;i++){
if(v[i]<=n) u[v[i]]=;
while(u[now]) now++;
ans+=(mex[i]=now);
}
// for(rg int i=1;i<=n;i++) printf("%d ",mex[i]);
// printf("ans=%lld\n",ans);
build(,,n);
for(rg int i=;i<=n;i++){
update(,i+,nxt[i]-,v[i]);
ans+=query(,i+,n);
// printf("ans=%lld\n",ans);
}
printf("%lld\n",ans);
}
return ;
}
HDU 4747 Mex【线段树上二分+扫描线】的更多相关文章
- hdu 5930 GCD 线段树上二分/ 强行合并维护信息
from NOIP2016模拟题28 题目大意 n个点的序列,权值\(<=10^6\) q个操作 1.单点修改 2.求所有区间gcd中,不同数个数 分析 1.以一个点为端点,向左或向右的gcd种 ...
- hdu 4747 mex 线段树+思维
http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意: 我们定义mex(l,r)表示一个序列a[l]....a[r]中没有出现过得最小的非负整数, 然后我 ...
- hdu 4747 Mex( 线段树? 不,区间处理就行(dp?))
Mex Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- HDU 4747 Mex ( 线段树好题 + 思路 )
参考:http://www.cnblogs.com/oyking/p/3323306.html 相当不错的思路,膜拜之~ 个人理解改日补充. #include <cstdio> #incl ...
- HDU 4747 Mex 递推/线段树
题目链接: acm.hdu.edu.cn/showproblem.php?pid=4747 Mex Time Limit: 15000/5000 MS (Java/Others)Memory Limi ...
- LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路+线段树上二分
题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...
- 贪心+离散化+线段树上二分。。。 Samara University ACM ICPC 2016-2017 Quarterfinal Qualification Contest G. Of Zorcs and Axes
题目链接:http://codeforces.com/gym/101149/problem/G 题目大意:给你n对数字,为(a[i], b[i]),给你m对数字,为(w[i], c[i]).给n对数字 ...
- 【BZOJ】4293: [PA2015]Siano 线段树上二分
[题意]给定n棵高度初始为0的草,每天每棵草会长高a[i],m次收割,每次在d[i]天将所有>b[i]的草收割到b[i],求每次收割量.n<=500000. [算法]线段树上二分 [题解] ...
- [NOIP2015模拟10.27] [JZOJ4270] 魔道研究 解题报告(动态开点+权值线段树上二分)
Description “我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力.”——<The Grimoire of Marisa>雾雨魔理 ...
随机推荐
- 30行JavaScript代码实现一个比特币量化策略
精简极致的均线策略 30行打造一个正向收益系统 原帖地址:https://www.fmz.com/bbs-topic-new/262 没错!你听的没错是30行代码!仅仅30行小编我习惯先通篇来看看 代 ...
- Golang 在 Linux CentOS 6.5 服务器上实现 博客后台程序开机启动
在linux下想实现开机启动的方法很多,这里我采用了在/etc/rc.local里写shell指令的方式. 以下就以我的实际操作为例子讲述,很多地方需要看官自己调整信息哦! 1.在/etc/rc.lo ...
- 《Windows核心编程系列》十三谈谈在应用程序中使用虚拟内存
在应用程序中使用虚拟内存 Windows提供了以下三种机制对内存进行操控: 一:虚拟内存.最适合来管理大型对象数据或大型结构数组. 二:内存映射文件.最适合用来管理大型数据流,以及在同一机 器上运行的 ...
- QT5每日一学(二)编写QT多窗口程序
一.添加主窗口 1.首先打开Qt Creator,新建Qt Widgets Application,项目名称设置为windows,在类信息界面保持基类为QMainWindow.类名为MainWindo ...
- 题解报告:hdu 1075 What Are You Talking About
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1075 Problem Description Ignatius is so lucky that he ...
- TestNG基本注解(一)
TestNG基本注解 注解 描述 @BeforeSuite 注解的方法将只运行一次,运行所有测试前此套件中. @AfterSuite 注解的方法将只运行一次此套件中的所有测试都运行之后. @Bef ...
- vijos P1629八 容斥原理
https://vijos.org/p/1629 注意lcm要用LL 先给一个样例 1 2 1 10 思路.其实这题就是问,给定一堆数,要求不能整除其任意一个的数字有多少个. 容辞 + lcm dfs ...
- OAuth 开放授权 Open Authorization
http://oauth.net/ http://tools.ietf.org/html/rfc6749 http://reg.163.com/help/help_oauth2.html 网易通行证O ...
- AJPFX关于通过索引获取最大值的思路
/*** 通过索引获取最大值***/public class Test1 { public static void main(String[] args) { ...
- hihocoder offer收割编程练习赛12 B 一面砖墙
思路: 就是求哪个长度出现的次数最多. 实现: #include <iostream> #include <cstdio> #include <algorithm> ...