题意:给定一个数组A,然后进行两种操作 1.对 a,b区间内任意i,如果(i-a)%k==0,则将Ai的值加上c;2.输入任意a,输出Aa的值。
思路:线段树
1<=k<=10
因为线段树只能存连续的数,单点/区间,查询,修改。
题目说要间隔几个数再增加。
所以想到多建几棵树。
具体是1+2+3+…+10棵。
由余数和除数决定。
k=1时,mod=0;
k=2时,mod=0、1;
k=10时,mod=0、1、…、9
总共55个。
#define MAX 50050
#define mid (l+r)/2
int seg[MAX*4];
int num[MAX];
int lazy[MAX*4][55];
int d[11][11];
int n;
int m;
两个操作:
1.区间修改:
a,b, c,k
由a和k可以将这一段唯一地确定下来(是55个中的哪一个。
找到相应的区间就加上c.
延迟更新。
在查询操作中才更新到deg的值
void change_inter_val(int a,int b,int c,int k,int mo,int l,int r,int st){
if(a<=l&&r<=b){
lazy[st][d[k][mo]]+=c;
return;
}
if(a<=mid) change_inter_val(a,b,c,k,mo,l,mid,ls);
if(b>mid) change_inter_val(a,b,c,k,mo,mid+1,r,rs);
}
2.单点查询:
每一点涉及到55个线段树,所以要根据k和mod来加和。
此时将lazy数组更新。
下传。
int ask_point(int x,int l,int r,int st){
if(l==r){
for(int i=1;i<=10;i++){
seg[st]+=lazy[st][d[i][x%i]];
lazy[st][d[i][x%i]]=0;
}
return seg[st];
}
down(x,st);
if(x<=mid) return ask_point(x,l,mid,ls);
else return ask_point(x,mid+1,r,rs);
}
下传:
void down(int x,int st){//膜k余mod的同一列树标记下放。例如:2 4 6 8 10
for(int i=1;i<=10;i++){
int mod=x%i;
if(lazy[st][d[i][mod]]){
lazy[rs][d[i][mod]]+=lazy[st][d[i][mod]];
lazy[ls][d[i][mod]]+=lazy[st][d[i][mod]];
lazy[st][d[i][mod]]=0;
}
}
}
完整代码:
#include <iostream>
#include "vector"
#include "string"
#include "algorithm"
#include "queue"
//#include "unordered_map"
#define ll long long
#define inf 0x3f3f3f3f
#define ls st<<1
#define rs st<<1|1
using namespace std;
#define MAX 50050
#define mid (l+r)/2
int seg[MAX*4];
int num[MAX];
int lazy[MAX*4][55];
int d[11][11];
int n;
int m;
void build(int l,int r,int st){
for(int i=0;i<55;i++) lazy[st][i]=0;
if(l==r) {
seg[st]=num[l];
return;
}
if(l<=mid) build(l,mid,ls);
if(r>mid) build(mid+1,r,rs);
}
void down(int x,int st){//膜k余mod的同一列树标记下放。例如:2 4 6 8 10
for(int i=1;i<=10;i++){
int mod=x%i;
if(lazy[st][d[i][mod]]){
lazy[rs][d[i][mod]]+=lazy[st][d[i][mod]];
lazy[ls][d[i][mod]]+=lazy[st][d[i][mod]];
lazy[st][d[i][mod]]=0;
}
}
}
int ask_point(int x,int l,int r,int st){
if(l==r){
for(int i=1;i<=10;i++){
seg[st]+=lazy[st][d[i][x%i]];
lazy[st][d[i][x%i]]=0;
}
return seg[st];
}
down(x,st);
if(x<=mid) return ask_point(x,l,mid,ls);
else return ask_point(x,mid+1,r,rs);
}
void change_inter_val(int a,int b,int c,int k,int mo,int l,int r,int st){
if(a<=l&&r<=b){
lazy[st][d[k][mo]]+=c;
return;
}
if(a<=mid) change_inter_val(a,b,c,k,mo,l,mid,ls);
if(b>mid) change_inter_val(a,b,c,k,mo,mid+1,r,rs);
}
void init(){
int i;
for(i=1;i<=n;i++) {
scanf("%d",&num[i]);
}
build(1,n,1);
scanf("%d",&m);
}
int main(){
int i,a,b,c,k;
int tot=0;
for(i=1;i<=10;i++){
for(a=0;a<i;a++){
d[i][a]=tot++;
}
}
while (scanf("%d",&n)!=EOF){
init();
while(m--){
scanf("%d",&i);
if(i==2) {
scanf("%d",&a);
printf("%d\n",ask_point(a,1,n,1));
}
else {
scanf("%d%d%d%d",&a,&b,&k,&c);
change_inter_val(a,b,c,k,a%k,1,n,1);
}
}
}
}
利用lazy数组,延缓更新deg的值,只在查询的时候更新。