1. 程式人生 > >【LibreOJ 6278】 數列分塊入門 2 (分塊)

【LibreOJ 6278】 數列分塊入門 2 (分塊)

題目原址

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

code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#define ll long long
using namespace std;

int rd() {
    int x=0,f=1;char ch=getchar();
    while
(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAX=50010; int n,blo; int v[MAX],tag[MAX],bl[MAX]; vector <int> vec[505]; void reset(int x) { vec[x].clear(); for(int i=(x-1)*blo+1;i<=min(x
*blo,n);i++) vec[x].push_back(v[i]); sort(vec[x].begin(),vec[x].end()); } void add(int a,int b,int c) { for(int i=a;i<=min(bl[a]*blo,b);i++) v[i]+=c; reset(bl[a]); if(bl[a]!=bl[b]) { for(int i=(bl[b]-1)*blo+1;i<=b;i++) v[i]+=c; reset(bl[b]); } for
(int i=bl[a]+1;i<=bl[b]-1;i++) tag[i]+=c; } int query(int l,int r,int c) { int ans=0; for(int i=l;i<=min(bl[l]*blo,r);i++) if(v[i]+tag[bl[l]]<c) ans++; if(bl[l]!=bl[r]) for(int i=(bl[r]-1)*blo+1;i<=r;i++) if(v[i]+tag[bl[r]]<c) ans++; for(int i=bl[l]+1;i<=bl[r]-1;i++) { int x=c-tag[i]; ans+=lower_bound(vec[i].begin(),vec[i].end(),x)-vec[i].begin(); } return ans; } int main() { n=rd(),blo=sqrt(n); for(int i=1;i<=n;i++) v[i]=rd(); for(int i=1;i<=n;i++) { bl[i]=(i-1)/blo+1; vec[bl[i]].push_back(v[i]); } for(int i=1;i<=bl[n];i++) sort(vec[i].begin(),vec[i].end()); for(int i=1;i<=n;i++) { int opt=rd(),l=rd(),r=rd(),c=rd(); if(!opt) add(l,r,c); else printf("%d\n",query(l,r,c*c)); } return 0; }