题意:维护一个整数序列,支持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; }