HDU-4747 二分+线段树
题意:给出长度为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 二分+线段树的更多相关文章
- hdu 4747 mex 线段树+思维
http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意: 我们定义mex(l,r)表示一个序列a[l]....a[r]中没有出现过得最小的非负整数, 然后我 ...
- hdu 4747【线段树-成段更新】.cpp
题意: 给出一个有n个数的数列,并定义mex(l, r)表示数列中第l个元素到第r个元素中第一个没有出现的最小非负整数. 求出这个数列中所有mex的值. 思路: 可以看出对于一个数列,mex(r, r ...
- HDU 6070 二分+线段树
Dirt Ratio Time Limit: 18000/9000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Tot ...
- 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 ...
- K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)
大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置. 这是一篇很好的题解: https://blog.csdn.net/sdauguanweihong/article/ ...
- hdu6070 Dirt Ratio 二分+线段树
/** 题目:hdu6070 Dirt Ratio 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6070 题意:给定n个数,求1.0*x/y最小是多少.x ...
- HDU4614 Vases and Flowers 二分+线段树
分析:感觉一看就是二分+线段树,没啥好想的,唯一注意,当开始摆花时,注意和最多能放的比大小 #include<iostream> #include<cmath> #includ ...
- hdu 4031 attack 线段树区间更新
Attack Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)Total Subm ...
- hdu 4288 离线线段树+间隔求和
Coder Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Su ...
随机推荐
- Vue小白篇 - Vue 的指令系统 (1) v-text、v-html
v-text:相当于innerText v-html:相当于innerHTML <div id="box"> {{ msg }} <div v-text=&quo ...
- sigmoid 和 soft-max总结
1)sigmoid函数(也叫逻辑斯谛函数): 引用wiki百科的定义: A logistic function or logistic curve is a common “S” shape (si ...
- 【虚拟机】:"该虚拟机似乎正在使用中。 如果该虚拟机未在使用,请按“获取所有权(T)”按钮获取它的所有权。否则,请按“取消(C)”按钮以防损坏。"
1.可能是由于上次使用虚拟机,没有正常关闭出现了这种情况,于是把问题复制粘贴搜了一下. 2.出现了如下可行的解决方法:把后缀名为.vmdk.lck的都删除掉. 3.然后再打开虚拟机就可以了.
- 转载 Tomcat集群配置学习篇-----分布式应用
Tomcat集群配置学习篇-----分布式应用 现目前基于javaWeb开发的应用系统已经比比皆是,尤其是电子商务网站,要想网站发展壮大,那么必然就得能够承受住庞大的网站访问量:大家知道如果服务器访问 ...
- SSD的理解,为PyramidBox做准备
目标检测主流方法有两大类 two-stage,以rcnn系列为主,采用建议框的方式对目标进行预测,过程首先要经过网络生成候选框,分类背景前景与进行第一次回归,之后再进行一次精细回归. 优点是准确率高, ...
- TCP练习
然后基本的socket编程,用TCP做两个进程互相发消息.C端主动发hello,S端收到后回world. #include <stdio.h> #include <stdlib.h& ...
- C#排列组合类,写彩票算法的朋友们可以来看一看
public class PermutationAndCombination<T> { /// <summary> /// 交换两个变量 ...
- 探索Redis设计与实现6:Redis内部数据结构详解——skiplist
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- 通过泛型,将string转换为指定类型
Generic TryParse You should use the TypeDescriptor class: public static T Convert<T>(this stri ...
- JS-动态加载
var s = document.createElement('script'); s.setAttribute('src', ''); s.setAttribute('type', 'text/ja ...