思路:开始直接用标记,最后发现他们是离散的点。几乎就相当于单点更行了。欧。
为何放弃治疗。。。
最后看的是 http://blog.csdn.net/ophunter/article/details/9455723
很详细。LCM 最小公倍数学长还是很狂拽酷炫的。
哎。我已可入灵魂。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define MAXN 50005 #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e using namespace std; int cnt[] = {0,0,1,3,6,10,15,21,28,36,45};//记录每一个K对应的MOD的起点 int n; int tree[MAXN*3][55];//K(1~10) 每一个K都有0~k-1的mod值 所以就是55棵线段树 void pushdown(int num,int id) { if(tree[num][id]) { tree[num<<1][id]+=tree[num][id]; tree[num<<1|1][id]+=tree[num][id]; tree[num][id]=0; } } void build(int num,int s,int e) { memset(tree[num],0,sizeof(tree[num])); if(s==e) { int a; scanf("%d",&a); tree[num][0]=a; return; } int mid=(s+e)>>1; build(lson); build(rson); } void update(int num,int s,int e,int l,int r,int val,int id) { if(l<=s && r>=e) { tree[num][id]+=val; return; } int mid=(s+e)>>1; pushdown(num,id); if(l<=mid)update(lson,l,r,val,id); if(r>mid)update(rson,l,r,val,id); } int query(int num,int s,int e,int tag,int id) { if(s==e) return tree[num][id]; int mid=(s+e)>>1; pushdown(num,id); if(tag>mid)return query(rson,tag,id); else if(tag<=mid)return query(lson,tag,id); } int main() { while(scanf("%d",&n)!=EOF) { build(1,1,n); int op; scanf("%d",&op); while(op--) { int ope; scanf("%d",&ope); if(ope==2) { int a,ans=0; scanf("%d",&a); for(int i=1;i<=10;i++) { int id=cnt[i] + a%i;//(i-a)%k==0 ==> i%k==a%k... ans+=query(1,1,n,a,id);//线段树上记录的是ADD } printf("%d\n",ans); } else { int a,b,k,c; scanf("%d%d%d%d",&a,&b,&k,&c); int id = cnt[k] + a%k;//找到对应的树 update(1,1,n,a,b,c,id); } } } return 0; }