题目大意:
给定一个一段区间,让你执行两种操作,一种是加入一种是查询。
题解:根据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;
}
本文介绍了一种使用树状数组优化区间操作的方法,通过建立特定数量的树状数组来实现高效的修改和查询操作,具体包括建立树状数组的数量、操作流程以及复杂度分析。
974

被折叠的 条评论
为什么被折叠?



