啦啦啦。

这是杭州网赛的一个题目,当时没做出来,当然这个想法确实比较难想到。

题目质量很高,这个题目也很特别,以前都没做过类似的题目。让我又一次体验了线段树的强大力量。

题目的意思是给你n个数a1-an。对于任何一个区间[l,r],它所对应的值为这个区间内没有出现的最小非负整数,求所有1<=L<=R<=n的区间所对应的值的总和。

比赛的时候苦思无果,以为是什么高端的数据结构或者很奇怪的算法,后来才发现自己坑了。

题目其实是这样的,在最开始预处理所有1开头的(即L=1的所有区间的值,然后从1开始每次都删除一个数,并且更新区间,每次都求一次和,然后就没有然后了,把每次更新后的区间所要求的和加起来就是答案了哦。

这个想法是没有错的,但是实现起来十分的麻烦。我也是经历了若干发TLE,WA,RE以后最终内牛满面地A掉了此题,以此作为纪念。

再讲讲具体是怎么实现的吧!其实预处理的话可以用数组模拟链表来实现,时间非常快(就像建图那种方法),但是由于Ai可能给的很大,所以我们用哈希来实现快速查询啊。记录每个数下一次出现的位置。如果没有出现,那么下一次出现的位置为n+1就好了。

假设当前我已经统计好了Ai作为起点的值,现在要统计Ai+1作为起点的值?应该怎么做?怎么更新呢?

是这样的。找到Ai+1下一次出现的地方的前一位。如果它所对应的那个函数值比当前的小,那说明不用更新了(想想问什么?因为说明有比当前数更小的数没有出现,所以无需更新,而在出现以后的地方显然又已经存在Ai在前面了。)

如果那个数的值大于当前的值,则说明可以修改更新。但是在更新前要先查一下从哪一步开始查找,就二分查找啦,找到第一个大于Ai的数。然后更新区间就可以了。

记得每次删除一个数Ai都要把query(i+1,pos)  的值加到ans里面哦。

总的时间复杂度是:n*log(n)*log(n)。Dangerous !!!

上代码吧:(注意用long long)

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#define maxn 200200
#define ll long long
using namespace std; int a[maxn],b[maxn],col[*maxn],next[maxn],cur;
int n,m,k,t,pos;
ll ans,sum[*maxn];
map<int,int> ss;
bool visit[maxn]; void PushDown(int rt,int l,int r)
{
if (col[rt]==-) return;
col[rt<<]=col[rt<<|]=col[rt];
int mid=(l+r)>>;
sum[rt<<]=col[rt]*(mid-l+);
sum[rt<<|]=col[rt]*(r-mid);
col[rt]=-;
} void PushUp(int rt)
{
sum[rt]=sum[rt<<]+sum[rt<<|];
} void build(int rt,int l,int r)
{
col[rt]=-;
if (l==r) { sum[rt]=b[l]; return ; }
int mid=(l+r)>>;
build(rt<<,l,mid);
build(rt<<|,mid+,r);
PushUp(rt);
} void update(int rt,int l,int r,int L,int R,int id)
{
if (L>R) return;
if (L<=l && R>=r)
{
sum[rt]=id*(r-l+);
col[rt]=id;
return ;
}
PushDown(rt,l,r);
int mid=(l+r)>>;
if (L<=mid) update(rt<<,l,mid,L,R,id);
if (R> mid) update(rt<<|,mid+,r,L,R,id);
PushUp(rt);
} ll query(int rt,int l,int r,int L,int R)
{
if (L>R) return ;
if (L<=l && R>=r) return sum[rt];
PushDown(rt,l,r);
int mid=(l+r)>>;
ll tot=;
if (L<=mid) tot=query(rt<<,l,mid,L,R);
if (R> mid) tot+=query(rt<<|,mid+,r,L,R);
return tot;
} int find(int l,int r,int id)
{
int mid;
while (l<r)
{
mid=(l+r)>>;
if (query(,,n,mid,mid)<=id) l=mid+;
else r=mid;
}
return l;
} int main()
{
while (scanf("%d",&n) && (n))
{
ss.clear();
for (int i=; i<=n; i++) scanf("%d",&a[i]);
memset(visit,false,sizeof visit);
for (int i=n; i>=; i--)
{
if (ss[a[i]]!=) next[i]=ss[a[i]];
else next[i]=n+;
ss[a[i]]=i;
}
cur=;
for (int i=; i<=n; i++)
{
if (a[i]<maxn) visit[a[i]]=true;
while (visit[cur]) cur++;
b[i]=cur;
}
build(,,n);
ans=sum[];
for (int i=; i<n; i++)
{
pos=min(next[i]-,n);
if (i+<=pos)
if (query(,,n,pos,pos)>a[i])
{
k=find(i+,pos,a[i]);
update(,,n,k,pos,a[i]);
}
ans+=query(,,n,i+,n);
}
printf("%I64d\n",ans);
}
return ;
}

HDU4747——2013 ACM/ICPC Asia Regional Hangzhou Online的更多相关文章

  1. hdu 4747 Mex (2013 ACM/ICPC Asia Regional Hangzhou Online)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 思路: 比赛打得太菜了,不想写....线段树莽一下 实现代码: #include<iost ...

  2. [2013 ACM/ICPC Asia Regional Hangzhou Online J/1010]hdu 4747 Mex (线段树)

    题意: + ;];;;], seg[rt <<  | ]);)) * fa.setv;) * fa.setv;;], seg[rt <<  | ], r - l + );;,  ...

  3. 2013 ACM/ICPC Asia Regional Hangzhou Online hdu4739 Zhuge Liang's Mines

    Zhuge Liang's Mines Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  4. HDU4745——Two Rabbits——2013 ACM/ICPC Asia Regional Hangzhou Online

    这个题目虽然在比赛的时候苦思无果,但是赛后再做就真的是个水题,赤果果的水题. 题目的意思是给n个数构成的环,两只兔子从任一点开始分别顺逆时针跳,每次可以调到任意一个数(最多不会跳过一圈). 求最多能跳 ...

  5. HDU 4745 Two Rabbits(最长回文子序列)(2013 ACM/ICPC Asia Regional Hangzhou Online)

    Description Long long ago, there lived two rabbits Tom and Jerry in the forest. On a sunny afternoon ...

  6. HDU 4744 Starloop System(最小费用最大流)(2013 ACM/ICPC Asia Regional Hangzhou Online)

    Description At the end of the 200013 th year of the Galaxy era, the war between Carbon-based lives a ...

  7. HDU 4747 Mex(线段树)(2013 ACM/ICPC Asia Regional Hangzhou Online)

    Problem Description Mex is a function on a set of integers, which is universally used for impartial ...

  8. hduoj 4710 Balls Rearrangement 2013 ACM/ICPC Asia Regional Online —— Warmup

    http://acm.hdu.edu.cn/showproblem.php?pid=4710 Balls Rearrangement Time Limit: 6000/3000 MS (Java/Ot ...

  9. hduoj 4708 Rotation Lock Puzzle 2013 ACM/ICPC Asia Regional Online —— Warmup

    http://acm.hdu.edu.cn/showproblem.php?pid=4708 Rotation Lock Puzzle Time Limit: 2000/1000 MS (Java/O ...

随机推荐

  1. 20155310 2016-2017-2 《Java程序设计》第十周学习总结

    20155310 2016-2017-2 <Java程序设计>第十周学习总结 教材学习内容总结 网络编程 •网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.程序员所作的事情就 ...

  2. banwagon vps装wordpress

    http://www.banwagong.com/213.html http://www.banwagong.com/225.html http://www.banwagong.com/230.htm ...

  3. 【SDOI2014】数表

    题面 题解 不管$a$的限制 我们要求的东西是:($\sigma(x)$是$x$的约数个数和) $ \sum_{i=1}^n\sum_{j=1}^m\sigma(gcd(i,j)) $ 设$f(x)= ...

  4. m2eclipse安装遇到的问题——备忘

    手贱把m2eclipse给卸载了,结果重新安装的时候,发现原来的网址不好用了,去官网查了发现改成了http://download.eclipse.org/technology/m2e/releases ...

  5. 【linux】vim常用快捷键(转)

    原文链接:https://www.cnblogs.com/tianyajuanke/archive/2012/04/25/2470002.html 1.vim ~/.vimrc 进入配置文件 如果不知 ...

  6. 六、Django之Template

    一.Template由来 1.任何前端页面的改动都和后端有关: 2.前端HTML和后端python分开能让网站更加清晰: 3.前后端分离的趋势下,专业的事交给专业的人做. 二.Django中的temp ...

  7. 「Leetcode」974. Subarray Sums Divisible by K(Java)

    分析 这题场上前缀和都想出来了,然后就没有然后了...哭惹.jpg 前缀和相减能够得到任意一段连续区间的和,然后他们取余\(K\)看余数是否为0就能得到.这是朴素的遍历算法.那么反过来说,如果两个前缀 ...

  8. CentOS 6.8 安装JDK8

    JDK安装 1.查看环境是否有默认jdk,输入命令: rpm -qa | grep jdk 如果有默认jdk,可以使用 yum remove 删除 2.进入系统根目录,创建developer文件夹 3 ...

  9. python模块的作用和说明

    Python模块 如果你从Python解释器退出并再次进入,之前的定义(函数和变量)都会丢失.因此,如果你想编写一个稍长些的程序,最好使用文本编辑器为解释器准备输入并将该文件作为输入运行.这被称作编写 ...

  10. 账号被锁无法ssh登陆

    Account locked due to failed logins 方法一: 使用root用户登陆后执行: pam_tally2 --user=username --reset 方法二: user ...