题意:给出长度为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 ;
}

最新文章

  1. Linear Algebra Lecture5 note
  2. [JavaEE]Get请求URI中带的中文参数在服务端乱码问题的解决方法
  3. linux之php
  4. CsvHelper
  5. WebLogic Exception
  6. C# 数组,ArrayList与List对象的区别
  7. OpenStack学习
  8. [娱乐]GameMaker绘制参数方程的图像
  9. python带cookie提交表单自动登录(转)
  10. 基于 Consul 的 Docker Swarm 服务发现
  11. C语言一维数组转换为二维数组
  12. 百度地图JS调用示例
  13. LNMP搭建环境遇到的N多坑
  14. C++中输出流的刷新问题和 endl和 \n的区别
  15. 题解 P3871 【[TJOI2010]中位数】
  16. dtNavMeshQuery::findLocalNeighbourhood m_tinyNodePool-&gt;getNode dtHashRef整数哈希 getPortalPoints dtOverlapPolyPoly2D
  17. Debian 系统安装 Nagios 服务器监控端
  18. 深度森林DeepForest
  19. 01-学前入门VS各个组成部分
  20. Android Studio 1.0RC1版公布

热门文章

  1. 2019-9-29-dotnet-对-DateTime-排序
  2. 一、bootstrap-select输入选择框
  3. 中州韵输入法(rime)导入搜狗词库
  4. 【串线篇】浅谈BeanFactory
  5. 解决PageHelper.startPage(page, size)后,关于PageInfo的total等属性不正确等问题
  6. 查找服务器的真实ip
  7. java web项目的https配置
  8. 使用node-static运行vue打包文件dist
  9. 为什么不能在shell脚本中执行source /etc/profile或者source ~/.bashrc问题?
  10. Linux系统之-介绍,主要特性