区域赛的线段树 好题
题面是区间[a,b]里面满足(i+a)%k==0的就更新
然后想一想 其实就是从a开始每隔几个进行更新 也就是说要把区间划分成连续的段 方便成段更新
假设现在k==1 那么每次更新的时候就是连续的那一段 因为每个点都要更新
k==2 那么就有两种情况 奇数段和偶数段
依此类推------》一共有1+2+3+。。。+10=55种情况
那么就要用55棵树来维护每一种情况
每次更新针对其中的一棵树的一段进行更新
那么如何统计呢 我们发现每一个下标数字在一种k的划分种只出现一次 那么就说明了它的更新和就是每一个k划分中的
一种划分所得到的值
比如点2
在k=1时就是第1段
k=2时就是第二段
后面其实都是第二段
所以只要把对应的10种情况相加即可
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
#define maxn 55555
int lazy[maxn],sum[maxn<<2][55];
int pos[11][11];
int n,m,a,b,c,k,x=0,op;
void down(int rt,int l,int r){
if(lazy[rt]){
lazy[rs]=lazy[ls]=lazy[rt];
for(int i=0;i<55;++i){
sum[ls][i]+=sum[rt][i];
sum[rs][i]+=sum[rt][i];
sum[rt][i]=0;
}
lazy[rt]=0;
}
}
void build(int rt,int l,int r){
for(int i=0;i<55;++i){sum[rt][i]=0;}
lazy[rt]=0;
if(l==r)return ;
build(ls,l,mid);
build(rs,mid+1,r);
}
void ins(int rt,int l,int r,int L,int R,int a,int k,int w){
if(L<=l&&r<=R){
lazy[rt]=1;
sum[rt][pos[k][a%k]]+=w;
return ;
}
if(L<=mid)ins(ls,l,mid,L,R,a,k,w);
if(mid<R)ins(rs,mid+1,r,L,R,a,k,w);
}
int query(int rt,int l,int r,int L,int R,int a){
if(L<=l&&r<=R){
int ans=0;
for(int i=1;i<=10;++i)ans+=sum[rt][pos[i][a%i]];
return ans;
}
down(rt,l,r);
int ans=0;
if(L<=mid)ans+=query(ls,l,mid,L,R,a);
if(mid<R)ans+=query(rs,mid+1,r,L,R,a);
return ans;
}
int s[maxn];
int main(){
for(int i=1;i<=10;++i) //k
for(int j=0;j<i;++j) //a%k
pos[i][j]=x++;
while(~scanf("%d",&n)){
for(int i=1;i<=n;++i)scanf("%d",&s[i]);
build(1,1,n);
scanf("%d",&m);
while(m--){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d%d",&a,&b,&k,&c);
ins(1,1,n,a,b,a,k,c);
}
else if(op==2){
scanf("%d",&a);
printf("%d\n",query(1,1,n,a,a,a)+s[a]);
}
}
}
return 0;
}
本文介绍了一道区域赛线段树题目,讨论了如何通过将区间[a,b]内的元素按照(i+a)%k==0的条件进行更新,并通过划分不同段来优化更新操作。文章提出使用55棵线段树分别维护不同的更新情况,给出具体实现代码。

1233

被折叠的 条评论
为什么被折叠?



