HDOJ 4267 A Simple Problem with Integers

题意:维护一个整数序列,支持2种操作:

1 a b k c将区间[a b]中满足(i-a)%k==0的数加上c;

2 x查询第x个数的值。

数据范围:整数个数N<=50000,操作次数Q<=50000,1<=k<=10

分析:此题关键在于处理修改操作,我们发现修改是等间隔的,所以可以将数组拆开如下:

k=1时,间隔为0:

1 2 3 4 5 6 7 8 9 10……

k=2时,间隔为1:

1 3 5 7 9 ……

2 4 6 8 10……

k=3时,间隔为2:

1 4 7 10……

2 5 8 ……

3 6 9 ……

按以上拆法,可以得到55个整数序列,每次修改都是对其中一个序列进行的连续修改,由于每个数均在10个序列中出现,所以查询操作是10个序列的查询结果的和。所以需用55棵线段树来维护这55个序列,由于N很大,可能会MLE,这时就要想到树状数组了……

View Code
#include <stdio.h>
#include <string.h>
#define N 50001
int a[N],n,m;
int d[10][10][N];
struct pro
{
    void init()
    {
        for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
        for(int i=0;i<10;i++)
        {
            for(int j=0;j<=i;j++)
            {
                memset(d[i][j],0,sizeof(d[0][0][0])*(n+1));
            }
        }
    }
    void query()
    {
        int x;
        scanf("%d",&x);
        int ans=a[x];
        for(int k=1;k<=10;k++)
        {
            int j=(x-1)%k;
            for(int i=(x-j-1)/k+1;i;i-=i&-i)
            {
                ans+=d[k-1][j][i];
            }
        }
        printf("%d\n",ans);
    }
    void update()
    {
        int x,y,k,z;
        scanf("%d%d%d%d",&x,&y,&k,&z);
        int j=(x-1)%k;
        for(int i=(x-j-1)/k+1;i<=n;i+=i&-i)    d[k-1][j][i]+=z;
        for(int i=(y-j-1)/k+2;i<=n;i+=i&-i)  d[k-1][j][i]-=z;
    }
}p;
int main()
{
    while(~scanf("%d",&n))
    {
        p.init();
        scanf("%d",&m);
        while(m--)
        {
            int opt;
            scanf("%d",&opt);
            if(opt==1)  p.update();
            else    p.query();
        }
    }
    return 0;
}

 

posted @ 2012-09-11 16:07  BeatLJ  阅读(181)  评论(0编辑  收藏  举报