动态开点线段树:
因为一开始想的是开k课线段树,但是发现它其实求的是相对于a的位置,而不是相对于1的位置,所以开k棵线段树无法将信息存完全
那么我们考虑为什么信息会丢失,是因为i%mo(1=<mo<=10)有mo个,所以我们也要将这些信息记录下来,那么总的信息个数就是
10+9+....+1=55个。所以我们开55棵线段树维护一下就好了。
这里建线段树用动态开点(有dalao学长直接用55棵线段树过了orz)
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#define lch a[n].lc
#define rch a[n].rc
using namespace std;
const int maxn=50010;
struct data {int rc,lc;long long ad;}a[220*maxn];
int nn,m,topt,root[11][12];
long long v[maxn];
void pushdown(int n)
{
if (a[n].ad)
{
if (!lch) lch=++topt; a[lch].ad+=a[n].ad;
if (!rch) rch=++topt; a[rch].ad+=a[n].ad;
a[n].ad=0;
}
}
void tree_add(int &n,int L,int R,int l,int r,long long k)
{
if (!n) n=++topt;
if (L==l && R==r) {a[n].ad+=k; return;}
pushdown(n); int mid=(L+R)>>1;
if (r<=mid) tree_add(lch,L,mid,l,r,k);
else if (l>=mid+1) tree_add(rch,mid+1,R,l,r,k);
else tree_add(lch,L,mid,l,mid,k),tree_add(rch,mid+1,R,mid+1,r,k);
}
long long qury(int &n,int l,int r,int lc)
{
if (!n) n=++topt;
if (l==r && r==lc) return a[n].ad;
pushdown(n); int mid=(l+r)>>1;
if (lc<=mid) return qury(lch,l,mid,lc);
else return qury(rch,mid+1,r,lc);
}
int main()
{
while (~scanf("%d",&nn))
{
for (int i=1;i<=topt;i++) a[i].ad=a[i].lc=a[i].rc=0;
memset(root,0,sizeof root); topt=0;
for (int i=1;i<=nn;i++) scanf("%lld",&v[i]);
scanf("%d",&m);
while (m--)
{
int ff; scanf("%d",&ff);
if (ff==1)
{
int xx,yy,k; long long c;
scanf("%d%d%d%lld",&xx,&yy,&k,&c); int mo=xx%k;
tree_add(root[xx%k][k],0,nn/k,(xx-mo)/k,(yy-mo)/k,c);
}
else
{
int lc; long long ans=0; scanf("%d",&lc);
for (int i=0;i<10;i++)
for (int j=1;j<=10;j++)
if (lc%j==i && root[i][j])
ans+=qury(root[i][j],0,nn/j,(lc-i)/j);
printf("%lld\n",ans+v[lc]);
}
}
}
return 0;
}