A Simple Problem with Integers POJ - 3468 (分块)

时间:2023-03-08 22:54:57
A Simple Problem with Integers POJ - 3468 (分块)

题目链接:https://cn.vjudge.net/problem/POJ-3468

题目大意:区间加减+区间查询操作。

具体思路:本来是一个线段树裸题,为了学习分块就按照分块的方法做吧。

分块真的好暴力,,,(但是还是挺优美的)。

说一下各个数组的作用。

a数组,代表每一个点的值。

sum数组,代表分块后每一段的值。

add数组,相当于线段树中的lazy标记,记录的数当前这一整段添加的值。

l数组,r数组,记录每一段的左端点和右端点。

belong数组,记录每一个数属于哪一个分块中。

AC代码:

 #include<iostream>
#include<stack>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<math.h>
using namespace std;
# define ll long long
const int maxn = 1e6+;
ll a[maxn],sum[maxn],add[maxn];
int l[maxn],r[maxn];
int belong[maxn];
void buildblock(int t){
int tmp=(int)sqrt(t*1.0);
int tot=t/tmp;
if(t%tmp)tot++;
for(int i=;i<=t;i++){
belong[i]=(i-)/tmp+;
}
for(int i=;i<=tot;i++){
l[i]=(i-)*tmp+;
r[i]=i*tmp;
}
r[tot]=t;
for(int i=;i<=tot;i++){
for(int j=l[i];j<=r[i];j++){
sum[i]+=a[j];
}
}
}
void update(int st,int ed,ll val){
if(belong[st]==belong[ed]){
for(int i=st;i<=ed;i++){
a[i]+=val;
sum[belong[st]]+=val;
}
return ;
}
for(int i=st;i<=r[belong[st]];i++){
a[i]+=val;
sum[belong[st]]+=val;
}
for(int i=l[belong[ed]];i<=ed;i++){
a[i]+=val;
sum[belong[ed]]+=val;
}
for(int i=belong[st]+;i<belong[ed];i++){
add[i]+=val;
}
}
ll ask(int st,int ed){
ll ans=;
if(belong[st]==belong[ed]){
for(int i=st;i<=ed;i++){
ans+=a[i]+add[belong[st]];
}
return ans;
}
for(int i=st;i<=r[belong[st]];i++){
ans+=a[i]+add[belong[st]];
}
for(int i=l[belong[ed]];i<=ed;i++){
ans+=a[i]+add[belong[ed]];
}
for(int i=belong[st]+;i<belong[ed];i++){
ans+=sum[i]+add[i]*(r[i]-l[i]+);
}
return ans;
}
int main(){
//freopen("hqx.in","r",stdin);
int n,m;
scanf("%d %d",&n,&m);
for(int i=;i<=n;i++){
scanf("%lld",&a[i]);
}
buildblock(n);
char str[];
int st,ed;
ll cost;
while(m--){
scanf("%s",str);
if(str[]=='Q'){
scanf("%d %d",&st,&ed);
printf("%lld\n",ask(st,ed));
}
else if(str[]=='C'){
scanf("%d %d %lld",&st,&ed,&cost);
update(st,ed,cost);
}
}
return ;
}