HDU 4267 A Simple Problem with Integers Regional Changchun Online

题目大意:

给定一个一段区间,让你执行两种操作,一种是加入一种是查询。

题解:根据k的值建立10类树状数组,每类中根据i%k的不同建立k棵树状数组,也就是55棵树状数组,这样每次修改操作只对其中1棵树状数组进行操作,所以是O(logN)的复杂度,每次查询只对其中10棵树状数组统计增量和,所以是O(10*logN)的复杂度。

55棵:k取1的mod有1个为0  k取2的mod有2个为1,0 以此类推,k取10的时候mod有0,1,2,3,4,5,6,7,8,9十个 所以共55个

取树状数组的in[100][MAXD] 对于每一个k取数组的10位开始

#include<iostream>
#define MAXD 50010
using namespace std;
int n,m,in[100][MAXD],a[MAXD]; 
int lowbit(int t)//求最小幂2^k 
{
	return t & (t^(t-1)); 
}
void insert(int k,int pos,int num)
{
	while(pos<=n)
	{ 
		in[k][pos]+=num; 
		pos+=lowbit(pos); 
	} 
}
int query(int id)
{
    int i, k, x, ans = 0;
    //从余数1开始扫到10 
    for(i = 1; i <= 10; ++i )
    {
		//对于每类k有i%k的类 
        k = (i - 1) * 10 + id % i;
		for(x = id; x > 0; x -= x & -x) ans += in[k][x];
    }
    return a[id] + ans;
}
void solve()
{
    int i, op, a, b, k, c;
    scanf("%d", &m);
    for(i = 0; i < m; ++i )
    {
        scanf("%d", &op);
        if(op == 1)
        {
            scanf("%d%d%d%d", &a, &b, &k, &c);
            //优化,因为实际取莫是因为a一直到a+nk,使得b为最后一个可以被余数取的数 
            b -= (b - a) % k;
            //对于每个k从数组10开始记录k的余数(例如k=4那么k的余数要0,1,2,3但是起始位置是30的下标开始) 
            insert(10 * (k - 1) + a % k, a, c);
            /*树状数组成段更新的弊端因为上面的insert相当于将a->∞都赋值为c
			那么后面我将b+1->∞赋值为-c那么就相当于将a->b赋值为c*/ 
			insert(10 * (k - 1) + b % k, b + 1, -c);
        }
        else if(op == 2)
        {
            scanf("%d", &a);
            printf("%d\n", query(a));
        }
    }
}
void init()
{
    int i, j;
    for(i = 1; i <= n; ++i ) scanf("%d", &a[i]);
   	memset(in,0,sizeof(in));
} 
int main()
{
	while(~scanf("%d", &n))
    {
        init();
        solve();
    }
    return 0;
}

你可能感兴趣的:(c,优化,query,insert)