zoukankan      html  css  js  c++  java
  • HDU4747——2013 ACM/ICPC Asia Regional Hangzhou Online

    啦啦啦。

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

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

    题目的意思是给你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)

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <map>
      5 #define maxn 200200
      6 #define ll long long
      7 using namespace std;
      8 
      9 int a[maxn],b[maxn],col[4*maxn],next[maxn],cur;
     10 int n,m,k,t,pos;
     11 ll ans,sum[4*maxn];
     12 map<int,int> ss;
     13 bool visit[maxn];
     14 
     15 void PushDown(int rt,int l,int r)
     16 {
     17     if (col[rt]==-1) return;
     18     col[rt<<1]=col[rt<<1|1]=col[rt];
     19     int mid=(l+r)>>1;
     20     sum[rt<<1]=col[rt]*(mid-l+1);
     21     sum[rt<<1|1]=col[rt]*(r-mid);
     22     col[rt]=-1;
     23 }
     24 
     25 void PushUp(int rt)
     26 {
     27     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
     28 }
     29 
     30 void build(int rt,int l,int r)
     31 {
     32     col[rt]=-1;
     33     if (l==r)  { sum[rt]=b[l]; return ; }
     34     int mid=(l+r)>>1;
     35     build(rt<<1,l,mid);
     36     build(rt<<1|1,mid+1,r);
     37     PushUp(rt);
     38 }
     39 
     40 void update(int rt,int l,int r,int L,int R,int id)
     41 {
     42     if (L>R) return;
     43     if (L<=l && R>=r)
     44     {
     45         sum[rt]=id*(r-l+1);
     46         col[rt]=id;
     47         return ;
     48     }
     49     PushDown(rt,l,r);
     50     int mid=(l+r)>>1;
     51     if (L<=mid) update(rt<<1,l,mid,L,R,id);
     52     if (R> mid) update(rt<<1|1,mid+1,r,L,R,id);
     53     PushUp(rt);
     54 }
     55 
     56 ll query(int rt,int l,int r,int L,int R)
     57 {
     58     if (L>R) return 0;
     59     if (L<=l && R>=r) return sum[rt];
     60     PushDown(rt,l,r);
     61     int mid=(l+r)>>1;
     62     ll tot=0;
     63     if (L<=mid) tot=query(rt<<1,l,mid,L,R);
     64     if (R> mid) tot+=query(rt<<1|1,mid+1,r,L,R);
     65     return tot;
     66 }
     67 
     68 int find(int l,int r,int id)
     69 {
     70     int mid;
     71     while (l<r)
     72     {
     73         mid=(l+r)>>1;
     74         if (query(1,1,n,mid,mid)<=id) l=mid+1;
     75             else r=mid;
     76     }
     77     return l;
     78 }
     79 
     80 int main()
     81 {
     82     while (scanf("%d",&n) && (n))
     83     {
     84         ss.clear();
     85         for (int i=1; i<=n; i++) scanf("%d",&a[i]);
     86         memset(visit,false,sizeof visit);
     87         for (int i=n; i>=1; i--)
     88         {
     89             if (ss[a[i]]!=0) next[i]=ss[a[i]];
     90                 else next[i]=n+1;
     91             ss[a[i]]=i;
     92         }
     93         cur=0;
     94         for (int i=1; i<=n; i++)
     95         {
     96             if (a[i]<maxn) visit[a[i]]=true;
     97             while (visit[cur]) cur++;
     98             b[i]=cur;
     99         }
    100         build(1,1,n);
    101         ans=sum[1];
    102         for (int i=1; i<n; i++)
    103         {
    104             pos=min(next[i]-1,n);
    105             if (i+1<=pos)
    106                 if (query(1,1,n,pos,pos)>a[i])
    107                 {
    108                     k=find(i+1,pos,a[i]);
    109                     update(1,1,n,k,pos,a[i]);
    110                 }
    111             ans+=query(1,1,n,i+1,n);
    112         }
    113         printf("%I64d
    ",ans);
    114     }
    115     return 0;
    116 }
    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    Java实现 洛谷 P1423 小玉在游泳
    Java设置session超时(失效)的时间
    How Tomcat works — 八、tomcat中的session管理
    三种常用的MySQL建表语句
    mysql和oracle的区别(功能性能、选择、使用它们时的sql等对比)
    oracle 基础表 mysql版
    oracle员工表和部门表基本操作
    Oracle
    java生成6位随机数
    用Ajax图片上传、预览、修改图片
  • 原文地址:https://www.cnblogs.com/lochan/p/3349131.html
Copyright © 2011-2022 走看看