http://acm.hdu.edu.cn/showproblem.php?pid=4747

题意:

我们定义mex(l,r)表示一个序列a[l]....a[r]中没有出现过得最小的非负整数, 然后我们给出一个长度为n的序列,求他所有的连续的子序列的mex(l,r)的和。

思路:

首先因为n的最大值就是2*10^5 所有我们字需要考虑200000之内的数就好了,然后O(2*n)可以求出(1,1),(1,2), (1,3),(1,4) ... (1,n)来 mex是不减的。

然后我们考虑将第一个数拿走我们就能够得到(2,2),(2,3) ......(2,n) , 如何求他们?下边给出图解:

下边是粘贴别人的,感觉有个例子很好理解。

例:           1, 6,0,2,3,1,4,3

初始mex 0, 0,2,3,4,4,5,5        mex[1,r]

删除1后   0,  0,1,1,1,4,5,5         mex[2,r]

……

当删除第一个1后,红色的mex不变!,紫色的mex值变为1,橙色的mex值不变,删除点的mex置0

因此,用线段树维护一个单调不递增队列,每次求和。查找位置时用二分。线段树延时标记即可。

ps:我这里二笔了一下,题意一下大家,lazy一定要出事化为-1,因为这里面有置0的操作。我因此wa好多次。。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x) (x) << 1
#define R(x) (x) << 1 | 1
#define MID(l, r) (l + r) >> 1
#define Min(x, y) (x) < (y) ? (x) : (y)
#define Max(x, y) (x) < (y) ? (y) : (x)
#define E(x) (1 << (x))
#define iabs(x) (x) < 0 ? -(x) : (x)
#define OUT(x) printf("%I64d\n", x)
#define keyTree (chd[chd[root][1]][0])
#define Read() freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout); #define M 100007
#define N 200017 using namespace std; int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1}; const int inf = 0x7f7f7f7f;
const int mod = 1000000007; const double eps = 1e-8; int mex[N],a[N],next[N];
int vis[N];
ll val[4*N], lz[4*N];
int n; void pushup(int rt)
{
val[rt] = val[rt<<1] + val[rt<<1|1];
}
void pushdown(int rt,int m)
{
if (lz[rt] != -1)
{
lz[rt<<1] = lz[rt<<1|1] = lz[rt];
val[rt<<1] = lz[rt] * (m - (m>>1));
val[rt<<1|1] = lz[rt] * (m>>1);
lz[rt] = -1;
}
}
void build(int l, int r, int rt)
{
lz[rt] = -1;
val[rt] = 0;
if (l == r)
{
val[rt] = mex[l];
return ;
}
int m = (l + r) >> 1;
build(lc); build(rc);
pushup(rt);
}
void update(int L, int R, ll sc, int l, int r, int rt)
{
if (l >= L && r <= R)
{
lz[rt] = sc;
val[rt] = sc*(r - l + 1);
return ;
}
pushdown(rt,r - l + 1);
int m = (l + r) >> 1;
if (L <= m) update(L,R,sc,lc);
if (R > m) update(L,R,sc,rc);
pushup(rt);
}
ll query(int pos, int l,int r, int rt)
{
if (l == r) return val[rt];
int m = (l + r) >> 1;
pushdown(rt, r - l + 1);
if (pos <= m) return query(pos,lc);
else return query(pos,rc);
}
int BSR(int l, int r, int v)
{
int ans = -1;
while (l <= r)
{
int mid = (l + r) >> 1;
if (query(mid,1,n,1) > v)
{
ans = mid;
r = mid - 1;
} else l = mid + 1;
}
return ans;
}
int main()
{
while (~scanf("%d",&n))
{
if (!n) break;
CL(vis,0); CL(next,0);
for (int i = 1; i <= n; ++i)
{
scanf("%d",&a[i]);
a[i] = min(a[i],200001);
if (vis[a[i]]) next[vis[a[i]]] = i;
vis[a[i]] = i;
}
for (int i = 1; i <= n; ++i) if (!next[i]) next[i] = n + 1;
CL(vis,0); int last = 0;
for (int i = 1; i <= n; ++i)
{
vis[a[i]] = 1;
while (true)
{
if (!vis[last])
{
mex[i] = last;
break;
}
last++;
}
}
build(1,n,1); ll ans = 0;
for (int i = 1; i <= n; ++i)
{
ans += val[1];
if (i == n) continue;
int l = i + 1;
int r = next[i] - 1;
int pos = BSR(l,r,a[i]);
if (pos != -1) update(pos, r, a[i], 1, n, 1);
update(i, i, 0, 1, n, 1);
}
printf("%I64d\n",ans);
}
return 0;
}

  

hdu 4747 mex 线段树+思维的更多相关文章

  1. hdu 4747 Mex( 线段树? 不,区间处理就行(dp?))

    Mex Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

  2. HDU 4747 Mex ( 线段树好题 + 思路 )

    参考:http://www.cnblogs.com/oyking/p/3323306.html 相当不错的思路,膜拜之~ 个人理解改日补充. #include <cstdio> #incl ...

  3. hdu 4747【线段树-成段更新】.cpp

    题意: 给出一个有n个数的数列,并定义mex(l, r)表示数列中第l个元素到第r个元素中第一个没有出现的最小非负整数. 求出这个数列中所有mex的值. 思路: 可以看出对于一个数列,mex(r, r ...

  4. hdu 3333 离线线段树 + 思维/树状数组 /在线主席树

    #include<iostream> #include<cstdio> #include<string> #include<cmath> #includ ...

  5. hdu 4031 attack 线段树区间更新

    Attack Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Subm ...

  6. hdu 4288 离线线段树+间隔求和

    Coder Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Su ...

  7. hdu 3016 dp+线段树

    Man Down Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  8. HDU 4747 Mex 递推/线段树

    题目链接: acm.hdu.edu.cn/showproblem.php?pid=4747 Mex Time Limit: 15000/5000 MS (Java/Others)Memory Limi ...

  9. HDU 4747 Mex (2013杭州网络赛1010题,线段树)

    Mex Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

随机推荐

  1. ios unrecognized selector sent to instance出现的原因和解决方案

    概述:造成unrecognized selector sent to instance iphone,大部分情况下是因为对象被提前release了,在你心里不希望他release的情况下,指针还在,对 ...

  2. ST-LINK使用注意

    利用ST-LINK下载程序注意事项: 1.接线 按照上面图对着自己的开发板连接相应的引脚就可以了. 2.keil5配置 线连接完之后,要对自己的工程进行相关的 配置才能正确进行下载. 首先选择ST-L ...

  3. 170629、springboot编程之Druid数据源和监控配置二

    上篇是一种配置方式,虽然我们创建了servlet.filter但是没有任务编码,看着是不是很不爽.ok,接下来说一下简介的配置方式,使用代码注册Servlet,也是我个人比较推荐的! 1.创建Drui ...

  4. 02Del.ashx(删除班级)

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using WebHelper ...

  5. 基于JDK1.8的LinkedList源码学习笔记

    LinkedList作为一种常用的List,是除了ArrayList之外最有用的List.其同样实现了List接口,但是除此之外它同样实现了Deque接口,而Deque是一个双端队列接口,其继承自Qu ...

  6. aliyun oss 文件上传 java.net.SocketTimeoutException Read timed out 问题分析及解决

    upload ClientException Read timed out com.aliyun.openservices.ClientException: Read timed out        ...

  7. mysql 数据操作 单表查询 group by 聚合函数 没有group by情况下

    聚合函数只能用在组里使用 #没有group by 则默认算作一组 取出所有员工的最高工资 mysql> select max(salary) from employee; +---------- ...

  8. phpstorm psr2样式.xml

    将如下内容保存为 .xml 格式 <code_scheme name="Default"> <PHPCodeStyleSettings> <optio ...

  9. java基础语法 List

    List:元素是有序的(怎么存的就怎么取出来,顺序不会乱),元素可以重复(角标1上有个3,角标2上也可以有个3)因为该集合体系有索引, ArrayList:底层的数据结构使用的是数组结构(数组长度是可 ...

  10. (17)ClippingNode的使用

    概述 ClippingNode(裁剪节点)可以用来对节点进行裁剪,可以根据一个模板切割图片的节点,生成任何形状的节点显示. ClippingNode是Node的子类,可以像普通节点一样放入Layer, ...