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 200017using 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;
}

  

转载于:https://www.cnblogs.com/E-star/p/3348552.html

hdu 4747 mex 线段树+思维相关推荐

  1. Doom HDU - 5239(线段树+思维)

    THE END IS COMINGGGGGG! Mike has got stuck on a mystery machine. If he cannot solve this problem, he ...

  2. HDU 2795 Billboard (线段树+贪心)

    HDU 2795 Billboard (线段树+贪心) 手动博客搬家:本文发表于20170822 21:30:17, 原地址https://blog.csdn.net/suncongbo/articl ...

  3. HDU - 4747 Mex(线段树)

    题意: 计算    其中mex即为博弈中出现的mex(未出现的最小非负整数). 分析: 有两种方法,递推有点懵(以后再来补QAQ),就写了线段树 想法是每次求以i为起点的区间的mex值的和,最后累加即 ...

  4. 线段树——思维(Codeforces 339D Xenia and Bit Operations/Billboard HDU - 2795)

    Codeforces 339D Xenia and Bit Operations vj地址 题意:给出2的n次方个数,每次将现在这个序列中相邻的两个数运算后合并为一个数,得到一个新的序列,这个新序列的 ...

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

    [题意概述] 一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和. [题解] 扫描线+线段树. 我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到 ...

  6. HDU - 6602 Longest Subarray(线段树+思维)

    题目链接:点击查看 题目大意:给出一个长度为 n 的序列,每个数字的范围是 [ 1 , C ] ,现在需要求一个子串,使得字串中的字母,要么出现 0 次,要么出现至少 K 次,问这个子串的最大长度是多 ...

  7. HDU - 6315 Naive Operations(线段树+思维)

    题目链接:点击查看 题目大意:给出一个数列 a 和一个数列 b ,其中数列 a 初始时全部为 0 ,数列 b 初始时是一个 1 ~ n 的排列,接下来共有 m 次操作,每次操作分为两种: add l ...

  8. HDU - 6992 Lawn of the Dead 线段树 + 思维

    传送门 文章目录 题意: 思路: 题意: 给你一张n∗mn*mn∗m的图,其中有kkk个点不能走,你只能向下和向右走,问你能到达多少点. n,m,k≤1e5n,m,k\le1e5n,m,k≤1e5 思 ...

  9. 牛客 - 牛牛的mex(主席树/思维)

    题目链接:点击查看 题目大意:给出一个长度为 n 的排列,再给出 m 次询问,每次询问需要回答区间 [ l , r ] 的 mex 题目分析:算是一道比较经典的题目了吧,先说一般做法,一般做法是 nl ...

最新文章

  1. PHP开发移动端接口(增强版)
  2. sharedpreferences 重启不保存_MMKV为什么可以替换SharedPreferences
  3. Coursera公开课笔记: 斯坦福大学机器学习第六课“逻辑回归(Logistic Regression)”
  4. 如何汉化 OpenERP 6.1 日历视图
  5. pat天梯赛练习 L2-006
  6. matlab 一维 平滑,一维加噪信号的平滑处理(3)
  7. Android日志[进阶篇]三-Logcat 命令行工具
  8. C#退出窗体的总结方法
  9. 解密GaussDB(for Influx)时序洞察
  10. 51nod1297 管理二叉树
  11. JAVA中Long与Integer
  12. ECMAScript 学习笔记02
  13. 生信过程中的各种文件格式
  14. RGB转灰度的几种算法
  15. 2021字节秋招算法岗面经——抖音推荐
  16. CentOS7.6安装MySQL5.7
  17. 网络爬虫技术是什么,网络爬虫的基本工作流程是什么?
  18. python从入门到实践 练习题雨滴下落--我的下落时全都连在一起了---已解决
  19. YOLOv2—passthrough层
  20. ArcGIS教程 - 附录 - ArcGIS快捷键

热门文章

  1. ubuntu使用root权限登录的设置方法
  2. Hibernate延时加载
  3. bash shell脚本访问PostgreSQL的三种方式
  4. C++ 类成员引用变量的使用
  5. linux unix域socket_Socket通信原理
  6. tez什么意思_传统数仓和大数据数仓的区别是什么?
  7. centos yum安装_centos7上yum安装碰到的坑
  8. PHP中怎样实现正负数的相加,PHP 求任意n个正负整数里面最大的连续和
  9. 渗透测试-验证码的爆破与绕过
  10. 记一次应急响应到溯源入侵者