1. 程式人生 > >#6278. 數列分塊入門 2

#6278. 數列分塊入門 2

輸入 答案 msu ret 暴力 ack () main sub

題目描述

給出一個長為 nnn 的數列,以及 nnn 個操作,操作涉及區間加法,詢問區間內小於某個值 xxx 的元素個數。

輸入格式

第一行輸入一個數字 nnn。

第二行輸入 nnn 個數字,第 iii 個數字為 aia_iai?,以空格隔開。

接下來輸入 nnn 行詢問,每行輸入四個數字 opt\mathrm{opt}opt、lll、rrr、ccc,以空格隔開。

opt=0\mathrm{opt} = 0opt=0,表示將位於 [l,r][l, r][l,r] 的之間的數字都加 ccc。

opt=1\mathrm{opt} = 1opt=1,表示詢問 [l,r][l, r][l,r] 中,小於 c2c^2c2 的數字的個數。

輸出格式

對於每次詢問,輸出一行一個數字表示答案。

樣例

樣例輸入

4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2

樣例輸出

3
0
2

數據範圍與提示

對於100%的數據,1<=n<=50000, -2^31<=others,ans<=2^31-1。

思路:第一題是查詢一個數的,而這題是要在一個區間內找到一個比c*c小的值。暴力一個一個找

肯定是會超時的。我們可以接著第一題分塊的思路查詢,左右不足一塊的排序暴力找就行了,而整塊的

我們排序二分找就很快了。這裏要再建一個數組(這裏用的vector,因為二分可以用庫函數lower_bound())保存改變的值用來排序。

代碼:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define inf 0x3f3f3f3f
#include<vector>
#include<set>
#include<map>
#include<bits/stdc++.h>
typedef 
long long ll; using namespace std; const int maxn=5e4+10; int n,block,a[maxn],b[maxn],pos[maxn],x,ans; vector<int>v[550]; void reset(int x)//用來不構成一整塊的排序 { v[pos[x]].clear(); for(int i=(pos[x]-1)*block+1;i<=min(pos[x]*block,n);i++) v[pos[x]].push_back(a[i]); sort(v[pos[x]].begin(),v[pos[x]].end()); } void update(int l,int r,int c) { for(int i=l;i<=min(pos[l]*block,r);i++)//左邊不成一整塊,暴力加 a[i]+=c; reset(l); if(pos[l]!=pos[r]) { for(int i=(pos[r]-1)*block+1;i<=r;i++)//右邊不成一整塊的暴力加 a[i]+=c; reset(r); } for(int i=pos[l]+1;i<=pos[r]-1;i++)//中間整塊的整塊加,用b數組保存 b[i]+=c; } int query(int l,int r,int c)//查詢答案 { int ans=0; for(int i=l;i<=min(pos[l]*block,r);i++)//左邊不構成一整塊的暴力查找 if(a[i]+b[pos[l]]<c) ans++; if(pos[l]!=pos[r]) { for(int i=(pos[r]-1)*block+1;i<=r;i++)//右邊不構成一整塊的暴力查找 if(a[i]+b[pos[r]]<c) ans++; } for(int i=pos[l]+1;i<=pos[r]-1;i++)//中間整塊的二分查找 { int x=c-b[i]; ans+=lower_bound(v[i].begin(),v[i].end(),x)-v[i].begin(); } return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); block=sqrt(n); for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1,v[pos[i]].push_back(a[i]);//每個數分塊的序號,放入vector保存 for(int i=1;i<=pos[n];i++) sort(v[i].begin(),v[i].end());//整塊排序 int opt,l,r,x; for(int i=1;i<=n;i++) { scanf("%d%d%d%d",&opt,&l,&r,&x); if(opt==0) update(l,r,x); else printf("%d\n",query(l,r,x*x)); } return 0; }

#6278. 數列分塊入門 2