zoukankan      html  css  js  c++  java
  • spoj 3267 D-query

    题目链接:http://vjudge.net/problem/SPOJ-DQUERY

    ------------------------------------------------------------------------------

    主席树模板题之一 求不带修改的区间不同数个数

    最近学习了下发现主席树就是可持久化线段树 由于每次单点修改只会改变一条链上的信息

    所以我们可以把其余部分的信息重复利用 然后再新建一条链作为这次修改后的这条链的新状态

    所以每次单点修改的时间复杂度和空间复杂度都是$O(logN)$

    懂了原理后就像普通线段树一样按照自己的习惯来写就好 不需要准备什么模板

    而对于这种求区间不同的数的个数的问题 我们只需维护对于每种前缀区间 每个数最后一次出现位置

    然后所有最后一次出现位置对整个区间有$1$的贡献

    这样就可以根据询问的区间右端点对应的版本 用区间减法来求区间不同数的个数

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 3e4 + 10, T = N * 50, L = 1e6 + 10;
     4 int sum[T], ch[T][2], root[N << 1], ma[N], last[L];
     5 int croot, cnt, n, q;
     6 void build(int x, int L, int R)
     7 {
     8     if(L == R)
     9     {
    10         sum[x] = 0;
    11         return;    
    12     }
    13     int mid = (L + R) >> 1;
    14     ch[x][0] = ++cnt;
    15     build(cnt, L, mid);
    16     ch[x][1] = ++cnt;
    17     build(cnt, mid + 1, R);
    18     sum[x] = sum[ch[x][0]] + sum[ch[x][1]];
    19 }
    20 void update(int x, int L, int R, int y, int delta, int pre)
    21 {
    22     if(L == R)
    23     {
    24         sum[x] = sum[pre] + delta;
    25         return;
    26     }
    27     int mid = (L + R) >> 1;
    28     if(y <= mid)
    29     {
    30         ch[x][0] = ++cnt;
    31         update(cnt, L, mid, y, delta, ch[pre][0]);
    32         ch[x][1] = ch[pre][1];
    33     }
    34     else
    35     {
    36         ch[x][0] = ch[pre][0];
    37         ch[x][1] = ++cnt;
    38         update(cnt, mid + 1, R, y, delta, ch[pre][1]);
    39     }
    40     sum[x] = sum[ch[x][0]] + sum[ch[x][1]];
    41 }
    42 int query(int x, int L, int R, int r)
    43 {
    44     if(R <= r)
    45         return sum[x];
    46     int mid = (L + R) >> 1;
    47     if(r <= mid)
    48         return query(ch[x][0], L, mid, r);
    49     return
    50         sum[ch[x][0]] + query(ch[x][1], mid + 1, R, r);
    51 }
    52 int main()
    53 {
    54     scanf("%d", &n);
    55     root[++croot] = ++cnt;
    56     ma[0] = 1;
    57     build(cnt, 1, n);
    58     int x, y;
    59     for(int i = 1; i <= n; ++i)
    60     {
    61         scanf("%d", &x);
    62         root[++croot] = ++cnt;
    63         update(cnt, 1, n, i, 1, root[croot - 1]);
    64         if(last[x])
    65         {
    66             root[++croot] = ++cnt;
    67             update(cnt, 1, n, last[x], -1, root[croot - 1]);
    68         }
    69         last[x] = i;
    70         ma[i] = root[croot];
    71     }
    72     scanf("%d", &q);
    73     while(q--)
    74     {
    75         scanf("%d%d", &x, &y);
    76         if(x > 1)
    77             printf("%d
    ", sum[ma[y]] - query(ma[y], 1, n, x - 1));
    78         else
    79             printf("%d
    ", sum[ma[y]]);
    80     }
    81     return 0;
    82 }
  • 相关阅读:
    第三方支付——支付宝支付
    使用Ansible自动配置Nginx服务
    使用Ansible自动配置JDK环境
    mycat 生产环境 cpu 占用 800% 问题 Mycat调优启用useOffHeapForMerge报java.lang.NumberFormatException异常解决(附源码)
    es 备份 恢复
    修改es 副本数 replicas
    Java压缩流GZIPStream导致的内存泄露
    java 堆外内存泄漏 排查
    Linux下查看某一进程所占用内存的方法(转)
    jmap -histo java内存泄漏排查 -XX:MaxDirectMemorySize=2G
  • 原文地址:https://www.cnblogs.com/sagitta/p/5937253.html
Copyright © 2011-2022 走看看