zoukankan      html  css  js  c++  java
  • [SDOI2009]HH的项链

    OJ题号:BZOJ1878、洛谷1972

    思路:树状数组离线化。

    不难想到,对于一个[l,r]的区间,如果出现了多个相同的颜色,我们可以只关心在区间[l,r]中,该颜色最后一个贝壳。

    例如,对于形如{1,2,3,2,1}的项链,当我们询问区间[1,5]时,该项链等同于{0,0,3,2,1}(方便起见,这里用0表示空)。

    于是就有了以下的思路:当询问[l,r]时,答案即为区间[l,r]内新出现的贝壳的个数。

    显而易见,当新的贝壳出现时,原来的同色贝壳都会失效。

    那么问题来了,对于{1,2,3,2,1}这个项链,当我们询问[1,5]时,答案是3;当我们询问[1,3]时,答案也是3,但如果使用上面的方法,我们记录的是{0,0,3,2,1},输出的答案是1。怎么办?

    一种思路是使用可持久化数据结构,比如主席树(可持久化线段树)等。然而当时主席树似乎并没有被发明?

    这里介绍一种离散化做法。

    首先对所有的询问预处理,即以右端点r为关键字进行排序。

    建立一个树状数组,记录每个前缀新出现的贝壳的个数。

    当然树状数组并不能一次性建好,每次根据当前询问的r,加入位置≤r的所有贝壳(将树状数组中的位置标记为1),并删去相同颜色的贝壳(将树状数组中的位置标记为0)。

    然后发现洛谷上能A,在BZOJ上就RE了?

     最后发现的原因:代表颜色的数字不一定是连续的,而且可能会很大(编号为0到1000000之间的整数),所以直接开数组会爆,解决的方法是Hash(不方便)或者Map。

    RunID User Problem Result Memory Time Language Code_Length Submit_Time
    2084658 skylee 1878 Accepted 4668 kb 1488 ms C++/Edit 1324 B 2017-05-27 17:34:54
     1 #include<map>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<utility>
     5 #include<algorithm>
     6 #define r first
     7 #define l second.first
     8 #define id second.second
     9 typedef std::pair<int,std::pair<int,int> > Q;
    10 const int N=50001;
    11 int n;
    12 class FenwickTree {
    13     private:
    14         int val[N];
    15         int lowbit(const int x) {
    16             return x&-x;
    17         }
    18     public:
    19         FenwickTree() {
    20             memset(val,0,sizeof val);
    21         }
    22         void modify(int p,const int x) {
    23             while(p<=n) {
    24                 val[p]+=x;
    25                 p+=lowbit(p);
    26             }
    27         }
    28         int query(int p) {
    29             int ans=0;
    30             while(p) {
    31                 ans+=val[p];
    32                 p-=lowbit(p);
    33             }
    34             return ans;
    35         }
    36 };
    37 FenwickTree tree;
    38 int main() {
    39     scanf("%d",&n);
    40     int a[n+1];
    41     for(int i=1;i<=n;i++) {
    42         scanf("%d",&a[i]);
    43     }
    44     int m;
    45     scanf("%d",&m);
    46     Q q[m];
    47     for(int i=0;i<m;i++) {
    48         scanf("%d%d",&q[i].l,&q[i].r);
    49         q[i].id=i;
    50     }
    51     std::sort(&q[0],&q[m]);
    52     int p=1;
    53     std::map<int,int> last;
    54     int ans[m];
    55     for(int i=0;i<m;i++) {
    56         while(p<=q[i].r) {
    57             if(last[a[p]]) tree.modify(last[a[p]],-1);
    58             tree.modify(last[a[p]]=p,1);
    59             p++;
    60         }
    61         ans[q[i].id]=tree.query(q[i].r)-tree.query(q[i].l-1);
    62     }
    63     for(int i=0;i<m;i++) printf("%d
    ",ans[i]);
    64     return 0;
    65 }
  • 相关阅读:
    [复变函数]第07堂课 2.2 初等解析函数
    [家里蹲大学数学杂志]第237期Euler公式的美
    [家里蹲大学数学杂志]第287期复变函数讲义
    [家里蹲大学数学杂志]第253期实变函数讲义
    模仿王者荣耀的实时阴影
    Android 识别身份证号码(图片识别)
    基于swiper的移动端H5页面,丰富的动画效果
    基于skitter的轮播图炫酷效果,幻灯片的体验
    基于canvas的原生JS时钟效果
    .net core 实现简单爬虫—抓取博客园的博文列表
  • 原文地址:https://www.cnblogs.com/skylee03/p/6913749.html
Copyright © 2011-2022 走看看