1. 程式人生 > 實用技巧 >《演算法競賽進階指南》0x44分塊 POJ3468解法二

《演算法競賽進階指南》0x44分塊 POJ3468解法二

題目連結:https://www.acwing.com/problem/content/244/

樹狀陣列大約比分塊快上幾倍,分塊資料結構也具有很強的利用餘地,我們這個問題中,沒個分塊上有兩個屬性,一個是sum一個是add,其中一個分塊的sum域是真實的,但是其中的a[i]是不真實的,真實的a[i]是a[i]+add[pos[i]]。

程式碼:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn = 100010;
typedef long long ll;
int L[maxn],R[maxn]; ll a[maxn],sum[maxn],add[maxn]; int pos[maxn]; int n,m,t; void update(int l,int r,int C){ int p=pos[l],q=pos[r]; if(p==q){ for(int i=l;i<=r;i++)a[i]+=C; sum[p]+=C*(r-l+1); return; }else{ for(int i=p+1;i<=q-1;i++){ sum[i]
+=C*(R[i]-L[i]+1); add[i]+=C; } for(int i=l;i<=R[p];i++)a[i]+=C; sum[p]+=C*(R[p]-l+1); for(int i=L[q];i<=r;i++)a[i]+=C; sum[q]+=C*(r-L[q]+1); } } ll query(int l,int r){ ll ans=0; int p=pos[l],q=pos[r]; if(p==q){ for(int
i=l;i<=r;i++)ans+=a[i]; ans+=add[p]*(r-l+1); return ans; }else{ for(int i=p+1;i<=q-1;i++)ans+=sum[i]; for(int i=l;i<=R[p];i++)ans+=a[i]; ans+=add[p]*(R[p]-l+1); for(int i=L[q];i<=r;i++)ans+=a[i]; ans+=add[q]*(r-L[q]+1); return ans; } } int main(){ cin>>n>>m; for(int i=1;i<=n;i++)scanf("%lld",&a[i]); //構建分塊 t=sqrt(n*1.0); for(int i=1;i<=t;i++){ L[i]=(i-1)*t+1; R[i]=i*t; } if(R[t]<n)++t,L[t]=R[t-1]+1,R[t]=n; //設定分塊上的屬性,以及每個位置的歸屬 for(int i=1;i<=t;i++){ for(int j=L[i];j<=R[i];j++){ pos[j]=i; sum[i]+=a[j]; } add[i]=0; } while(m--){ char s[10]; int l,r,d; scanf("%s%d%d",s,&l,&r); if(s[0]=='C'){ scanf("%d",&d); update(l,r,d); }else{ printf("%lld\n",query(l,r)); } } return 0; }