zoukankan      html  css  js  c++  java
  • Necklace(树状数组+离线操作)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3874

    Necklace

    Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 3929    Accepted Submission(s): 1296


    Problem Description
    Mery has a beautiful necklace. The necklace is made up of N magic balls. Each ball has a beautiful value. The balls with the same beautiful value look the same, so if two or more balls have the same beautiful value, we just count it once. We define the beautiful value of some interval [x,y] as F(x,y). F(x,y) is calculated as the sum of the beautiful value from the xth ball to the yth ball and the same value is ONLY COUNTED ONCE. For example, if the necklace is 1 1 1 2 3 1, we have F(1,3)=1, F(2,4)=3, F(2,6)=6.

    Now Mery thinks the necklace is too long. She plans to take some continuous part of the necklace to build a new one. She wants to know each of the beautiful value of M continuous parts of the necklace. She will give you M intervals [L,R] (1<=L<=R<=N) and you must tell her F(L,R) of them.
     
    Input
    The first line is T(T<=10), representing the number of test cases.
      For each case, the first line is a number N,1 <=N <=50000, indicating the number of the magic balls. The second line contains N non-negative integer numbers not greater 1000000, representing the beautiful value of the N balls. The third line has a number M, 1 <=M <=200000, meaning the nunber of the queries. Each of the next M lines contains L and R, the query.
     
    Output
    For each query, output a line contains an integer number, representing the result of the query.
     
    Sample Input
    2 6 1 2 3 4 3 5 3 1 2 3 5 2 6 6 1 1 1 2 3 5 3 1 1 2 4 3 5
     
    Sample Output
    3 7 14 1 3 6
     
    题意: 求区间不重复元素和
    题解: 询问是5个0 所以肯定要找一种可以扫描一次得出结果不会重复计算的算法,这里介绍一种巧妙的方法: 离线操作,所谓离线就是将所有的询问都读如后,根据需要进行排序,这里一定要记录一个id来保存输入的顺序,然后一个ans数组按照输入顺序储存答案,然后从左到右的扫描一边将所有的以当前扫描的点为终止点的答案都保存起来,最后按顺序输出ans 数组即可
      对于这个题:一般按照右端点排序,因为右端点代表这一个查询的结束,所以按右端点排序有特殊的意义,因为每次要去除重复的数字,可以考虑设一个last数组,标记其在之前是否出现过,如果出现过的化,将之前出现的地方的这个值更改成0 然后last数组的当前值更新成当前的位置,这样树状数组中存放的值就肯定没有重复元素了。
    这种离线的思想很重要,一定要利用好将所有的数据排序后每次可以将相同的结尾的值一起算出来的性质,指针只用扫描一边,每向后扫描后都将以这个值结尾的所有结果都处理出来。离线最大的好处是在依次向后更新last数组的时候前面的与其相关的询问已经处理过了,所以去除前面的值,保留后面的不会影响前面的结果,也不会影响后面的计算。如果不离线,last 数组如果这样更新的话,会影响到再次涉及前面的区间的和
     
    代码:
     
     
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 #define N 1000005
     6 #define M 50005
     7 #define numq 200005
     8 #define ll long long 
     9 int Last[N];
    10 ll shusz[M];
    11 int gaga[M];
    12 ll ans[numq];
    13 struct Q {
    14     int l ;
    15     int r;
    16     int id;
    17     bool operator < (const Q a) const
    18     {
    19         return r<a.r;
    20     }
    21 }qq[numq];
    22 int lb(int i)
    23 {
    24     return i&(-i);
    25 }
    26 void add(int j , int t)
    27 {
    28     for(int i =j ;i < M ;i+=lb(i))
    29     {
    30         shusz[i]+=t;
    31     }
    32 }
    33 ll sum (int x)
    34 {
    35     ll ans = 0 ;
    36     for(int i = x ; i > 0 ; i-=lb(i))
    37     {
    38         ans+=shusz[i];
    39     }
    40     return ans;
    41 }
    42 ll sum(int x , int y)
    43 {
    44     ll ans = sum(y)-sum(x-1);//注意是x-1
    45     return ans;
    46 }
    47 int main()
    48 {
    49     int T ;
    50     scanf("%d",&T);
    51     for(int i =0 ;i < T ; i++)
    52     {
    53         int n;
    54         scanf("%d",&n);
    55         int tm;
    56         for(int j = 1 ; j <= n ; j++)
    57         {
    58             scanf("%d",&tm);
    59             gaga[j] = tm;
    60         }
    61         int m ;
    62         scanf("%d",&m);
    63         for(int j = 1 ;j <= m ;j++)
    64         {
    65             int l , r ;
    66             scanf("%d%d",&l,&r);
    67             qq[j].l = l ;
    68             qq[j].r = r;
    69             qq[j].id = j;
    70         }
    71         memset(Last,-1,sizeof(Last));
    72         memset(ans,0,sizeof(ans));
    73         memset(shusz,0,sizeof(shusz));
    74         sort(qq+1,qq+m+1);
    75         int cur = 1;//记录扫描到第几个询问
    76         for(int j = 1 ; j <= n ; j++)//扫描n个点
    77         {
    78             if(Last[gaga[j]] != -1)
    79                 add(Last[gaga[j]], -gaga[j]);
    80             Last[gaga[j]] = j;
    81             add(j, gaga[j]);
    82             while(j == qq[cur].r)
    83             {
    84                 ans[qq[cur].id] = sum(qq[cur].l, qq[cur].r);
    85                 cur++;
    86             }
    87         }
    88         for(int j = 1; j <= m; j++)
    89             printf("%lld
    ", ans[j]);
    90     }
    91     return 0 ;
    92 }
  • 相关阅读:
    反射API(二)
    反射API(一)
    session一二事
    自定义session的存储机制
    JavaScript 入门笔记
    PHP引用赋值
    九九乘法口诀表
    PHP流程控制笔记
    PHP函数总结 (七)
    Linux程序编辑器习题汇总
  • 原文地址:https://www.cnblogs.com/shanyr/p/4725462.html
Copyright © 2011-2022 走看看