hdu 4267 A Simple Problem with Integers(线段树)

题意:N个数(N<=50000),A1~AN,有2种操作,1输出第i个数,2给从第a个到第b个数中(i-a)%k==0的增加一个值c.操作的次数<=50000。

分析:容易想到是线段树。树中每个节点开一个数组add[i][j],保存该区间对%i余j的数增加的值。查询的时候,把查找叶子节点i经过的节点所有对i增加的值累加,加上num[i]即是查询结果。这样更新和查询操作的时间复杂度都是O(nlogn)。

PS:该题容易超内存,开数组时要注意。

 1 #include <cstdio>
 2 #include <cstring>
 3 #define lson l,m,rt<<1
 4 #define rson m+1,r,rt<<1|1
 5 #define N 50010
 6 
 7 int num[N], add;
 8 int mod[N*3][55];
 9 int dir[11] = {00136101521283645};
10 
11 void update(int l, int r, int rt, int a, int b, int k, int c)
12 {
13     if(l>=a && r<=b)
14     {
15         int tmp = a%k;
16         mod[rt][dir[k]+tmp] += c;
17         return ;
18     }
19     if(l>b || r<a) return ;
20     int m = (l + r) >> 1;
21     update(lson,a,b,k,c);
22     update(rson,a,b,k,c);
23 }
24 
25 int query(int l, int r, int rt, int a)
26 {
27     int add = 0;
28     for(int i=1; i<=10; i++)
29         add += mod[rt][dir[i]+a%i];
30     if(l==r)
31     {
32         return add;
33     }
34     int m = (l + r) >> 1;
35     if(a<=m)
36     {
37         return query(lson, a) + add;
38     }
39     else
40         return query(rson, a) + add;
41 }
42 
43 int main()
44 {
45     int n, q, type, a, b, k, c;
46     while(scanf("%d",&n)!=EOF)
47     {
48         memset(mod, 0sizeof(mod));
49         for(int i=1; i<=n; i++)
50             scanf("%d",&num[i]);
51         scanf("%d",&q);
52         for(int i=1; i<=q; i++)
53         {
54             scanf("%d",&type);
55             if(type==2)
56             {
57                 scanf("%d",&a);
58                 printf("%d ",num[a]+query(1,n,1,a));
59             }
60             else if(type==1)
61             {
62                 scanf("%d%d%d%d",&a,&b,&k,&c);
63                 update(1,n,1,a,b,k,c);
64             }
65         }
66     }
67     return 0;
68 }
View Code
原文地址:https://www.cnblogs.com/byluoluo/p/3570887.html