HDU4267(2012年长春站)

这道题真的是好题,让我对线段树有了全新的认识,至少让我真正感受到了线段树的神奇。

题意是就是线段树区间更新,单点询问的问题,不过这个题好就好在它的区间更新的点并不连续!

adding c to each of Ai which satisfies a <= i <= b and (i - a) % k == 0.

关键在于更新的点所满足的条件  1.在区间[a,b]中。 2.关于k的余数与(a%k)相等。

其中第二个条件保证了更新的点不连续(但如果传统的先判断再更新,则线段树失去了优势,因为始终会超时)。

本题突破口在于K的大小(1 <= k <= 10),结合第二个条件,我们可以想到在线段树的 Lazy标记上做文章。

当k==1 余数有 0

当k==2 余数有 0,1

当k==3 余数有 0,1,2

。。。。。

可以看到,只有55种情况,那么我们只需要将线段树的 Lazy标记 扩充为大小55的数组,

然后根据相应的余数情况进行更新与查询即可。

  1 #include<iostream>
  2 #include<sstream>
  3 #include<stack>
  4 #include<cstdio>
  5 #include<cstdlib>
  6 #include<cstring>
  7 #include<climits>
  8 #include<cctype>
  9 #include<queue>
 10 #include<algorithm>
 11 #include<cmath>
 12 #include<map>
 13 #include<set>
 14 #define lson root<<1,l,mid
 15 #define rson root<<1|1,mid+1,r
 16 
 17 #define inf 0x3f3f3f3f
 18 #define N 50010
 19 #define maxn 10001000
 20 #define mod 1000000007
 21 using namespace std;
 22 
 23 int a[N];
 24 int b[11][11];     //用于将55种余数情况一 一 对 应
 25 struct NODE{
 26     int l,r;
 27     int v;
 28     int b[55];
 29     int mid(){
 30         return (l+r)>>1;
 31     }
 32 }node[N<<2];
 33 
 34 void build(int root,int l,int r)
 35 {
 36     node[root].l=l;
 37     node[root].r=r;
 38     node[root].v=0;
 39     memset(node[root].b,0,sizeof(node[root].b));
 40     if(l==r) return;
 41     int mid=node[root].mid();
 42     build(lson);
 43     build(rson);
 44 }
 45 
 46 void pushdown(int root)   //关于pushdown函数,个人觉得只需要询问时调用就行了,而且也过了,应该没问题,有的话请指出,谢谢
 47 {
 48     for(int i=1; i<=10; ++i)
 49     {
 50         for(int j=0; j<i; ++j)
 51         {
 52             node[root<<1].b[b[i][j]]+=node[root].b[b[i][j]];
 53             node[root<<1|1].b[b[i][j]]+=node[root].b[b[i][j]];
 54         }
 55     }
 56     memset(node[root].b,0,sizeof(node[root].b));
 57 }
 58 
 59 void update(int x,int y,int root,int v,int k,int rd)
 60 {
 61     if(node[root].l==x&&node[root].r==y)
 62     {
 63         node[root].b[b[k][rd]]+=v;
 64         node[root].v+=v;
 65         return;
 66     }
 67     int mid=node[root].mid();
 68     if(y<=mid) update(x,y,root<<1,v,k,rd);
 69     else if(x>mid) update(x,y,root<<1|1,v,k,rd);
 70     else
 71     {
 72         update(x,mid,root<<1,v,k,rd);
 73         update(mid+1,y,root<<1|1,v,k,rd);
 74     }
 75 }
 76 
 77 int query(int root,int x)
 78 {
 79     if(node[root].l==x&&node[root].r==x)
 80     {
 81         int ans=0;
 82         for(int i=1; i<=10; ++i)
 83             ans+=node[root].b[b[i][x%i]];
 84         return ans;
 85     }
 86     pushdown(root);
 87     int mid=node[root].mid();
 88     if(x<=mid) return query(root<<1,x);
 89     else return query(root<<1|1,x);
 90 }
 91 
 92 int main()
 93 {
 94    // freopen("lxx.txt","r",stdin);
 95     int group,figure,i,j,x,y,k,v,num;
 96     int cnt=0;
 97     for(i=1; i<=11; ++i)
 98         for(j=0; j<i; ++j)
 99             b[i][j]=cnt++;
100     while(~scanf("%d",&group))
101     {
102         build(1,1,group);
103         memset(a,0,sizeof(a));
104         for(i=1; i<=group; ++i) scanf("%d",&a[i]);
105         scanf("%d",&group);
106         while(group--)
107         {
108             scanf("%d",&num);
109             if(num==1)
110             {
111                 scanf("%d%d%d%d",&x,&y,&k,&v);
112                 update(x,y,1,v,k,x%k);
113             }
114             else
115             {
116                 scanf("%d",&figure);
117                 printf("%d
",query(1,figure)+a[figure]);
118             }
119         }
120     }
121     return 0;
122 }

不过感觉自己的代码风格还不够成熟,继续努力!