【HDU 4747 Mex】线段数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747
题意:有一组序列a[i](1<=i<=N), 让你求所有的mex(l,r), mex(l,r)表示区间[l,r]中最小的未在序列中出现的非负整数。
思路:冥思苦想半天无想法,白做了那么多线段树。 很明显的维护区间问题,容易想到线段树,比较难想到操作。 枚举一个序列的所mex(1,i),mex(2,i)……可以发现序列mex(x,i)是一个单调递增序列,我们需要求得就是所有以x开头的序列和,mex(x,i)(x<=i<=n)。这点确定了就好办了,记录每个位置的数后面最早重复出现的位置next[x],如果无则为设n+1。那么我们就可以发现,当第x个数所对应的序列 mex(x,i)(x<=i<=n)所对应的序列求完之后,删去此位置的数,位置x+1~next[x]-1序列中mex值大于a[x]的都改为a[x],因为a[x]没有了,下一个a[x]还未出现,所以可以证明这样做是正确的。从1到n扫一遍亦求出了所有的mex()。
基本上所有的操作都可以用到线段树。开始没有想到一点的是如何找序列中刚好大于a[x]的位置,并且此位置到next[x]-1赋值为a[x],怎么都没想到log(n)的操作,其实这里依然可以用到线段树,因为序列是单调递增的,另开一个区间维护序列mavv[u]表示区间中最大的mex值,随着询问以及其他操作成段更新即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstring>
#include <sstream>
using namespace std; #define lz 2*u,l,mid
#define rz 2*u+1,mid+1,r
typedef long long lld;
const int maxn=;
int a[maxn], b[maxn], next[maxn];
lld sum[*maxn], mavv[*maxn], flag[*maxn];
map<int,int>mp; void push_up(int u, int l, int r)
{
sum[u]=sum[*u]+sum[*u+];
mavv[u]=mavv[*u+];
} void push_down(int u, int l, int r)
{
int mid=(l+r)>>;
if(flag[u]!=-)
{
flag[*u]=flag[*u+]=flag[u];
mavv[*u]=mavv[*u+]=flag[u];
sum[*u]=(lld)(mid-l+)*flag[u];
sum[*u+]=(lld)(r-mid)*flag[u];
flag[u]=-;
}
} void build(int u, int l, int r)
{
flag[u]=-;
int mid=(l+r)>>;
if(l==r)
{
sum[u]=mavv[u]=b[l];
return ;
}
build(lz);
build(rz);
push_up(u,l,r);
} void Update(int u, int l, int r, int tl, int tr, int val)
{
if(tl>tr) return ;
if(tl<=l&&r<=tr)
{
mavv[u]=val;
sum[u]=(lld)val*(r-l+);
flag[u]=val;
return ;
}
push_down(u,l,r);
int mid=(l+r)>>;
if(tr<=mid) Update(lz,tl,tr,val);
else if(tl>mid) Update(rz,tl,tr,val);
else
{
Update(lz,tl,mid,val);
Update(rz,mid+,tr,val);
}
push_up(u,l,r);
} int find(int u, int l, int r, int tmp)
{
if(l==r) return l;
push_down(u,l,r);
int mid=(l+r)>>;
if(mavv[*u]>tmp) return find(lz,tmp);
else return find(rz,tmp);
} int main()
{
int n;
while(cin >> n,n)
{
for(int i=; i<=n; i++) scanf("%d",a+i);
mp.clear();
for(int i=n; i>=; i--)
{
if(mp[ a[i] ]) next[i]=mp[ a[i] ];
else next[i]=n+;
mp[ a[i] ]=i;
}
mp.clear();
int x=;
for(int i=; i<=n; i++)
{
mp[ a[i] ]=;
while(mp[x]) ++x;
b[i]=x;
}
build(,,n);
lld ans=;
for(int i=; i<=n; i++)
{
ans+=sum[];
if(mavv[]>a[i])
{
int id=find(,,n,a[i]);
Update(,,n,max(id,i+),next[i]-,a[i]);
}
Update(,,n,i,i,);
}
cout << ans <<endl;
}
}
【HDU 4747 Mex】线段数的更多相关文章
- 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 ...
- HDU 4747 Mex(线段树)(2013 ACM/ICPC Asia Regional Hangzhou Online)
Problem Description Mex is a function on a set of integers, which is universally used for impartial ...
- [HDU 4747] Mex (线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 这道题是我去年刚入校队的时候参加网赛的题目. 一年过去了,我依然还是不会做.. 这是我难题计划的 ...
- HDU 4747 Mex(线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意:给出一个数列A.计算所有的mex(i,j)之和.1<=i<=j<=n. ...
- HDU 4747 Mex (2013杭州网络赛1010题,线段树)
Mex Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- HDU 4747 Mex【线段树上二分+扫描线】
[题意概述] 一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和. [题解] 扫描线+线段树. 我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到 ...
随机推荐
- codeforces733D. Kostya the Sculptor 偏序cmp排序,数据结构hash,代码简化
对于n==100.1,1,2或者1,2,2大量重复的形状相同的数据,cmp函数最后一项如果表达式带等于,整个程序就会崩溃 还没有仔细分析std::sort的调用过程,所以这里不是很懂..,mark以后 ...
- sql 提取数字、字母、汉字
--提取数字 IF OBJECT_ID('DBO.GET_NUMBER2') IS NOT NULL DROP FUNCTION DBO.GET_NUMBER2 GO )) ) AS BEGIN BE ...
- Spark Streaming容错的改进和零数据丢失
本文来自Spark Streaming项目带头人 Tathagata Das的博客文章,他现在就职于Databricks公司.过去曾在UC Berkeley的AMPLab实验室进行大数据和Spark ...
- DrawerLayout的使用
一:首先是DrawerLayout的布局 <android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout& ...
- C#多线程编程总结
VS2008.C#3.0在WinForm开发中,我们通常不希望当窗体上点了某个按钮执行某个业务的时候,窗体就被卡死了,直到该业务执行完毕后才缓过来.一个最直接的方法便是使用多线程.多线程编程的方式在W ...
- c#写windows服务(转)
序言 前段时间做一个数据迁移项目,刚开始用B/S架构做的项目,但B/S要寄存在IIs中,而IIs又不稳定因素,如果重启IIs就要打开页面才能运行项目.有不便之处,就改用Windows服务实现.这篇就总 ...
- Flume内存溢出错误
java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:) at java.lang.Ab ...
- jquery事件重复绑定解决办法
一$.fn.live 重复绑定 解决:使用die()方法,在live()方法绑定前,将此元素上的前面被绑定的事件统统解除,然后再通过live()方法绑定新的事件. //先通过die()方法解除,再通过 ...
- C#/.NET Little Wonders: Use Cast() and OfType() to Change Sequence Type(zz)
Once again, in this series of posts I look at the parts of the .NET Framework that may seem trivial, ...
- CF# Educational Codeforces Round 3 C. Load Balancing
C. Load Balancing time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...