网赛的时候这题就不会做,现在有时间了又重新做了一下。由于我线段树做的本来就比较少,做这题的时候把题解看了半天也没看明白,后来通过问别人和自己想总算弄明白了。这题还是基于线段树的操作,但是在每个节点上要加一个额外的空间来表示有那些元素的值要增加,题目要求的是a到b区间中的,(i-a)%k==0的元素值要加c,那么就可以转化成i%k==a%k的元素,我们用add[i][j]来表示模k等于a%k的元素加C,每个节点都维护一个二维数组的话开销太大,这题的空间卡的很紧,考虑到a%k<k所以可以把空间压缩一半,这样就不会MLE了,添加的时候做一个lazy标记,然后更新和查询的时候都pushdown一下就好了……
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
#define MAXN 50005
struct Node
{
int l,r,lazy,add[55];
int mid()
{
return (l+r)>>1;
}
}tree[MAXN<<2];
int value[MAXN],number[11][11];
int n,q;
void build(int l,int r,int rt)
{
tree[rt].l=l;
tree[rt].r=r;
memset(tree[rt].add,0,sizeof(tree[rt].add));
tree[rt].lazy=0;
if(l==r) return;
build(l,tree[rt].mid(),rt<<1);
build(tree[rt].mid()+1,r,rt<<1|1);
}
void pushdown(int rt)
{
if(tree[rt].lazy)
{
tree[rt<<1].lazy+=tree[rt].lazy;
tree[rt<<1|1].lazy+=tree[rt].lazy;
tree[rt].lazy=0;
for(int i=0;i<55;i++)
{
tree[rt<<1].add[i]+=tree[rt].add[i];
tree[rt<<1|1].add[i]+=tree[rt].add[i];
tree[rt].add[i]=0;
}
}
}
void update(int L,int R,int k,int mod,int rt,int value)
{
if(L<=tree[rt].l&&tree[rt].r<=R)
{
tree[rt].lazy+=value;
tree[rt].add[number[k][mod]]+=value;
return;
}
pushdown(rt);
int mid=tree[rt].mid();
if(L<=mid)
update(L,R,k,mod,rt<<1,value);
if(R>mid)
update(L,R,k,mod,rt<<1|1,value);
}
int query(int pos,int rt)
{
int res;
if(tree[rt].l==tree[rt].r)
{
int temp=value[tree[rt].l];
for(int i=1;i<=10;i++)
{
temp+=tree[rt].add[number[i][pos%i]];
}
return temp;
}
pushdown(rt);
if(pos<=tree[rt].mid())
res=query(pos,rt<<1);
else res=query(pos,rt<<1|1);
return res;
}
int main()
{
//freopen("input.txt","r",stdin);
int tot=0;
for(int i=1;i<=10;i++)
for(int j=0;j<i;j++)
number[i][j]=tot++;
while(scanf("%d",&n)!=EOF)
{
build(1,n,1);
for(int i=1;i<=n;i++)
{
scanf("%d",&value[i]);
}
scanf("%d",&q);
while(q--)
{
int op;
scanf("%d",&op);
if(op==1)
{
int a,b,k,c;
scanf("%d%d%d%d",&a,&b,&k,&c);
update(a,b,k,a%k,1,c);
}
else
{
int pos;
scanf("%d",&pos);
printf("%d\n",query(pos,1));
}
}
}
}