zoukankan      html  css  js  c++  java
  • luogu P1972 [SDOI2009]HH的项链 树状数组

    之前只做过分块做法,补一下树状数组做法。

    我们先考虑一个问题,如何求从[1,x]这一区间内元素不同的个数?显然我们只要从到到位,遇到一个新的元素,就在对应位置+1,然后使用树状数组求前缀和即可。

    这里我们需要去求[x,y],所求区间的左端点也会发生变化。我们先按照[1,x]的方法预处理出这个前缀和数组。我们考虑对询问区间按照左端点排序。然后对于当前的区间[x0,y0],query(y0) - query(x0 - 1)与正确答案相比有所区别,是因为有些元素在x0左侧计算过了,而在这段区间中,对应第一次出现的位置没有+1。我们考虑能不能弥补这个错误呢。我们预处理出nxt[i],表示与位置i元素相同的右侧最近元素的下标。这样子,比如上一个区间为[x1,y1],下一个区间为[x2,y2],那么我们就让[x1,x2)这段区间中的每一个i的nxt[i]位置都对应+1。如果nxt[i]在[x1,x2)内,则不会对以后的答案造成影响,如果nxt[i]在[x2,]后,则显然修正了这个错误,并且在[i,x2)这段区间中,不会再有相同的元素了。

    忘记了树状数组的lowbit x & (-x)必须有括号。

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstring>
     4 using namespace std;
     5 struct qry
     6 {
     7     int l,r,id;
     8     friend bool operator < (qry a,qry b)
     9     {
    10         return a.l < b.l;
    11     }
    12 } vec[510000];
    13 int n,m;
    14 int num[510000],nxt[510000],hav[1100000],res[510000],sum[510000];
    15 int lowbit(int x)
    16 {
    17     return x & (-x);
    18 }
    19 void tre_insert(int x,int val)
    20 {
    21     for (int i = x;i <= n;i += lowbit(i))
    22         sum[i] += val;
    23 }
    24 int tre_qry(int x)
    25 {
    26     int tot = 0;
    27     for (int i = x;i;i -= lowbit(i))
    28         tot += sum[i];
    29     return tot;
    30 }
    31 int main()
    32 {
    33     scanf("%d",&n);
    34     for (int i = 1;i <= n;i++) 
    35         scanf("%d",&num[i]);
    36     scanf("%d",&m);
    37     for (int i = 1;i <= m;i++)
    38     {
    39         scanf("%d%d",&vec[i].l,&vec[i].r);
    40         vec[i].id = i;
    41     }
    42     sort(vec + 1,vec + m + 1);
    43     for (int i = 1;i <= n;i++)
    44         if (hav[num[i]] == 0)
    45         {
    46             hav[num[i]] = 1;
    47             tre_insert(i,1);
    48         }
    49     memset(hav,0,sizeof(hav));
    50     for (int i = n;i >= 1;i--)
    51     {
    52         if (hav[num[i]] == 0)
    53             nxt[i] = n + 1;
    54         else
    55             nxt[i] = hav[num[i]];
    56         hav[num[i]] = i;
    57     } 
    58     int t = 1;
    59     for (int i = 1;i <= m;i++)
    60     {    
    61         for (;t <= vec[i].l - 1;t++)
    62             tre_insert(nxt[t],1);
    63         res[vec[i].id] = tre_qry(vec[i].r) - tre_qry(vec[i].l - 1);
    64     }
    65     for (int i = 1;i <= m;i++)
    66         printf("%d
    ",res[i]);
    67     return 0;
    68 }
    心之所动 且就随缘去吧
  • 相关阅读:
    笔试的坑 onsubmit事件
    正则之
    笔试:找出一个字符串中字符出现最多的次数和该字符
    createDocumentFragment和insertAdjacentHTML
    css权威指南学习笔记--第七章
    使用gulp-minify-css的坑
    arguments[0]() 笔试题的坑
    快速搭建本地服务器
    voxel折腾指南
    力扣第72题 编辑距离
  • 原文地址:https://www.cnblogs.com/iat14/p/10507586.html
Copyright © 2011-2022 走看看