1. 程式人生 > >LibreOJ 6277. 數列分塊入門 1

LibreOJ 6277. 數列分塊入門 1

數組 void cnblogs print .... sca type iostream ring

題目鏈接:https://loj.ac/problem/6277

參考博客:https://www.cnblogs.com/stxy-ferryman/p/8547731.html

兩個操作,區間增加和單點查詢。

思路:將整個數組按照block(block=sqrt(n))分成許多小塊,lump[i]表示點i所在的塊,tag[i]表示編號為i的塊的增加值,如果是進行區間增加操作,我們一般可以把區間[l,r]分成三個部分,左邊不完整的區間(只含有某塊中的部分點),中間完整的區間(含有一些塊的所有點),右邊不完整的區間。這樣對於左右的不完整區間,他們的點的數量是比較少的,我們可以進行暴力更新,對於中間的完整區間,一般來說他們的點比較多,我們就用標記數組tag[i]來記錄第i塊裏增加的數,從而避免對太多的點進行單點更新。在單點查詢時,某個點的值就是本身數組的值加上這個點所在的塊的標記數組值(a[r]+tag[lump[r])。

點i所在的塊是lump[i]=(i-1)/block+1,表示lump[i]=i/block+1。

假設現在n=9,那麽block=sqrt(9)=3。

對1到9之間的點分塊,在i=3時,錯誤:3/3+1=2,3就在第二組 ,但是這是不對的,按理說3應該在第一組,怎麽辦,把3減1....

代碼:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include
<vector> #include<set> #include<cstdio> #include<string> #include<deque> using namespace std; typedef long long LL; #define eps 1e-8 #define INF 0x3f3f3f3f #define maxn 50005 /*struct point{ int u,w; }; bool operator <(const point &s1,const point &s2) { if(s1.w!=s2.w) return s1.w>s2.w; else return s1.u>s2.u; }
*/ int tag[maxn],a[maxn],lump[maxn]; int n,m,k,t,block; void add(int l,int r,int c)//這裏註意要把各個塊的邊界寫正確 { for(int i=l;i<=min(lump[l]*block,r);i++)//左邊的不完整的塊 暴力更新每個點 a[i]+=c; if(lump[l]!=lump[r])//左邊界和右邊界不在一個塊裏面 { for(int i=(lump[r]-1)*block+1;i<=r;i++)//右邊的不完整的塊 暴力更新 a[i]+=c; } for(int i=lump[l]+1;i<=lump[r]-1;i++)//中間的完整的塊的標記數組 增加值 tag[i]+=c; } int main() { scanf("%d",&n); block=sqrt(n); fill(tag,tag+maxn-1,0); for(int i=1;i<=n;i++)//給每個點分塊 lump[i]=(i-1)/block+1; for(int i=1;i<=n;i++) scanf("%d",&a[i]); int op,l,r,c; for(int i=1;i<=n;i++) { scanf("%d%d%d%d",&op,&l,&r,&c); if(op==0) add(l,r,c); else printf("%d\n",a[r]+tag[lump[r]]); } return 0; }

LibreOJ 6277. 數列分塊入門 1