题意:给出长度为n的序列,问任两个区间的mex运算结果的总和。

解法:直接讲线段树做法:我们注意到mex(1,1),mex(1,2),mex(1,3)...mex(1,i)的结果是单调不减的,那么我们考虑先用线段树维护上诉结果,那么此时以1为左端点的区间mex和就求出来了,重点来了:我们考虑怎么从以1为左端点的区间结果过渡到以2为结点的区间结果呢?我们注意到其实只要以1为端点的区间去掉a[1]这个点的影响就可以得到以2为端点的区间结果,那么我们怎样去除a[1]这个点的影响呢?我们发现去掉a[1]之后会影响到的就是位置1到下一个a[1]出现位置的这一段区间!这一段区间的结果如果mex>a[1],那么因为a[1]的删除它的结果就会变成a[1]。且我们上面提到mex(1,1)到mex(1,n)的结果是单调不减的。那么我们就可以在线段树上二分来找一个mex>a[1]的点,区间修改即可。这样下去一边统计答案一边删除数修改影响,到最后就可以AC了。

这道题的线段树解法还是比较经典的做法的,对于一类问题:询问的是任两个区间的结果总和,而且发现我们能比较快速地通过删除最前面的数使得结果快速过渡到下一个区间的结果,那么我们可以考虑使用这种像前缀线段树(这个简称是蒟蒻瞎掰的qwq)的做法。

细节详见代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+;
int n,a[N],f[N],nxt[N];
bool vis[N];
map<int,int> mp; LL sum[N<<],tag[N<<];
void pushup(int rt) {
sum[rt]=sum[rt<<]+sum[rt<<|];
}
void pushdown(int rt,int l1,int l2) {
if (tag[rt]==-) return;
sum[rt<<]=(LL)tag[rt]*l1; tag[rt<<]=tag[rt];
sum[rt<<|]=(LL)tag[rt]*l2; tag[rt<<|]=tag[rt];
tag[rt]=-;
}
void build(int rt,int l,int r) {
if (l==r) {
sum[rt]=f[l]; tag[rt]=-;
return;
}
sum[rt]=; tag[rt]=-;
int mid=l+r>>;
build(rt<<,l,mid);
build(rt<<|,mid+,r);
pushup(rt);
}
void update(int rt,int l,int r,int ql,int qr,int v) {
if (ql<=l && r<=qr) {
sum[rt]=(LL)v*(r-l+); tag[rt]=v;
return;
}
int mid=l+r>>;
pushdown(rt,mid-l+,r-mid);
if (ql<=mid) update(rt<<,l,mid,ql,qr,v);
if (qr>mid) update(rt<<|,mid+,r,ql,qr,v);
pushup(rt);
}
LL query(int rt,int l,int r,int ql,int qr) {
if (ql<=l && r<=qr) return sum[rt];
int mid=l+r>>;
pushdown(rt,mid-l+,r-mid);
LL ret=;
if (ql<=mid) ret+=query(rt<<,l,mid,ql,qr);
if (qr>mid) ret+=query(rt<<|,mid+,r,ql,qr);
return ret;
} int main()
{
while (scanf("%d",&n) && n) {
for (int i=;i<=n;i++) scanf("%d",&a[i]);
for (int i=;i<=n;i++) vis[i]=;
for (int i=;i<=n;i++) {
if (a[i]<=n) vis[a[i]]=;
f[i]=f[i-];
while (vis[f[i]]) f[i]++;
}
mp.clear();
for (int i=n;i;i--) {
if (mp.count(a[i])) nxt[i]=mp[a[i]]; else nxt[i]=n+;
mp[a[i]]=i;
}
build(,,n);
LL ans=;
for (int i=;i<=n;i++) {
ans+=query(,,n,i,n);
int l=i,r=nxt[i]-,t=a[i];
while (l<r) {
int mid=l+r>>;
if (query(,,n,mid,mid)>t) r=mid; else l=mid+;
}
if (query(,,n,r,r)>t)
update(,,n,r,nxt[i]-,a[i]);
}
printf("%lld\n",ans);
}
return ;
}

HDU-4747 二分+线段树的更多相关文章

  1. hdu 4747 mex 线段树+思维

    http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意: 我们定义mex(l,r)表示一个序列a[l]....a[r]中没有出现过得最小的非负整数, 然后我 ...

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

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

  3. HDU 6070 二分+线段树

    Dirt Ratio Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Tot ...

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

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

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

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

  6. K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)

    大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置. 这是一篇很好的题解: https://blog.csdn.net/sdauguanweihong/article/ ...

  7. hdu6070 Dirt Ratio 二分+线段树

    /** 题目:hdu6070 Dirt Ratio 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6070 题意:给定n个数,求1.0*x/y最小是多少.x ...

  8. HDU4614 Vases and Flowers 二分+线段树

    分析:感觉一看就是二分+线段树,没啥好想的,唯一注意,当开始摆花时,注意和最多能放的比大小 #include<iostream> #include<cmath> #includ ...

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

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

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

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

随机推荐

  1. linux100day(day6)--shell脚本简单逻辑

    if语句: if条件语句的使用格式: 1.单分支语句 if 条件;then 执行语句 fi 2.双分支语句 if 条件;then 执行语句1 else 执行语句2 fi 3.多分支语句 if 条件;t ...

  2. Ansible--04 ansible 流程控制

    ansible 流程控制 playbook 条件语句 不管是 shell 还是各大编程预言中,流程控制,条件判断都是必不可少的,在我们使用 Ansible的过程中,条件判断的使用频率都非常高. 例如: ...

  3. awk 起始位置和长度和 mf 一致

    1位开始 , 925开始 截取24 awk '{OFS="";print(substr($0,925,24),substr($0,1,24),substr($0,436,1),&q ...

  4. python 在图像上写中文字体 (python write Chinese in image)

    本人处理图像的时候经常使用opencv的包,但是 cv2.putText 显示不了中文,所以查找了如何在python在图像上写中文的方法,在伟大的Stack Overflow上面找到一个方法,分享给大 ...

  5. css text文本

    CSS 文本格式 文本格式 This text is styled with some of the text formatting properties. The heading uses the ...

  6. delphi 判断WIN8 , WIN8.1 , WIN10 系统版本

    今天测试了WIN8, WIN8.1, WIN10 系统下GetVersionEx 函数,居然取出来的版本都是6.2 . 于是网上查找各种获取内核版本号的方法, 终于找到几种有用的方法, 记录下来以作备 ...

  7. [NOIP模拟33]反思+题解

    又考了一次降智题…… 拿到T1秒出正解(可能是因为我高考数学数列学的海星?),分解质因数以后用等比数列求和计算每个因子的贡献.但是当时太过兴奋把最后的$ans \times =$打成了$ans +=$ ...

  8. MySQl 截取函数 left(),right(),substring(),substring_index() 的用法

    1. 字符串截取:left(str, length) mysql> select left('sqlstudy.com', 3); +-------------------------+ | l ...

  9. web开发小知识

    session共享机制:f5刷新是再次提交之前的数据请求 地址栏回车属于不同的请求 不同浏览器获取不到之前数据 同一浏览器可以获取同步数据 session注销:session.invalidate() ...

  10. os模块方法

    OS 对象方法: 提供了处理文件及目录的一系列方法 os.rename(current_file_name, new_file_name) 重命名 os.remove(file_name) 删除文件 ...