清点人数

清点人数(jdoj1427-vijos1320)

    题目大意:n个点,k个事件。每个事件为A , B , C。A表示查询该点的前缀和,B点是该点加权值,C点是该点减权值。

    注释:n<=500000,k<=100000,至少有30000个A

      想法:显然,单点修改,区间查询,数据范围较大,想到用一个较强的数据架构——线段树维护。而今天,我们来介绍一种特殊的数据结构——树状数组。

        接下来,我们来介绍树状数组的性质即特性。我们想线段树一样来理解树状数组。我们用 a[ ]来记录一段区间,A[]表示单点的权值。我们用一种特殊的想法——a[1]=A[1],a[2] = A [ 1 ] + A [ 2 ],a[3]=A[3] , a[4]=a[2]+a[3]+A[4].....那么,我们再次介绍一种位运算——lowbit,表示一个数的二进制表示中从末位开始的第一个非零数的位置的值,lowbit返回一个二的r次方 , r 便是那个值。由这个东西,我们就构架出整个树状数组的体系——一切的修改之间的差值为上一个值的lowbit,而lowbit可以简单的推出,为t&(-t),即,它表示的就是按位,取反,加一的全过程。这样,查询啊,修改啊什么的就全部可以在O(logn)的时间复杂度内实现。那么,我们发现,可以用树状数组实现的,线段树都可以做到,但,为什么我们仍然如此推崇树状数组?原因十分简单,好写!太jb好写了。比那个什么线段树的代码量小到不知道哪里去了。所以在此,极其推荐树状数组,而且比较好理解。

      我们回归这道题,我们想,每次单点修改,只会对后面产生贡献,所以,我们就可以对其后面的shu进行lowbit差值的修改,注意数据量,细心即可。

    最后,附上丑陋的代码......

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 int n;
 5 char a[5];
 6 int tree[500001];
 7 int lowbit(int t)
 8 {
 9     return t&(-t);
10 }
11 void add(int x,int y)
12 {
13     for(int i=x;i<=n;i+=lowbit(i))
14     {
15         tree[i]+=y;
16     }
17 }
18 void query(int x)
19 {
20     int ans=0;
21     for(int i=x;i;i-=lowbit(i))
22     {
23         ans+=tree[i];
24     }
25     printf("%d
",ans);
26 }
27 int main()
28 {
29     int m;
30     int x,y;
31     scanf("%d%d",&n,&m);
32     for(int i=1;i<=m;i++)
33     {
34         scanf("%s",a+1);
35         if(a[1]=='A')
36         {
37             scanf("%d",&x);
38             query(x);
39         }
40         else if(a[1]=='B')
41         {
42             scanf("%d%d",&x,&y);
43             add(x,y);
44         }
45         else
46         {
47             scanf("%d%d",&x,&y);
48             add(x,-y);
49         }
50     }
51     return 0;
52 }

    小结:错误

        1.记住,这时一个教训:lowbit函数完全可以写在for循环里面,没有必要单独列出,导致效率变低。

        2.printf与%c千万别在一起使!!

    转载请注明:http://www.cnblogs.com/ShuraK/p/7856899.html 

| 欢迎来原网站坐坐! >原文链接<

原文地址:https://www.cnblogs.com/ShuraK/p/7856899.html