zoukankan      html  css  js  c++  java
  • 【LOJ#6278】数列分块2

    题目大意:分块维护一个有 n 个数字的序列,有两种操作:区间加,区间查询小于某个数的元素个数。n <= 50000

    预处理阶段:处理出块内元素的相对大小顺序(排序),时间复杂度为 (O(nlogn))
    查询阶段:区间加过程中每次重构的时间复杂度为 (O(sqrt n*logsqrt n)),查询过程中每次时间复杂度为 (O(sqrt n)),一共 n 次操作。
    因此,总时间复杂度为 (O(n*logn+n*sqrt n*logsqrt n))
    注:该题无法用树套树进行维护,树套树一般仅支持单点修改,平衡树区间修改操作会很慢。
    分块比树套树优秀的地方在于维护的信息仅在块中处理即可,无需像树一样进行上传,即:无需考虑维护信息的区间合并性质。

    代码如下

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=5e4+10;
    const int maxb=800;
    
    inline int read(){
    	int x=0,f=1;char ch;
    	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    	return f*x;
    }
    
    int n,m,a[maxn];
    struct node{int l,r,add;}b[maxb];
    int tot,bl[maxn];vector<int> v[maxb];
    void make_block(){
    	tot=sqrt(n);
    	for(int i=1;i<=tot;i++)b[i].l=b[i-1].r+1,b[i].r=i*tot;
    	if(b[tot].r<n)++tot,b[tot].l=b[tot-1].r+1,b[tot].r=n;
    	for(int i=1;i<=tot;i++){
    		for(int j=b[i].l;j<=b[i].r;j++)bl[j]=i,v[i].push_back(a[j]);
    		sort(v[i].begin(),v[i].end());
    	}
    }
    inline void rebuild(int idx){
    	v[idx].clear();
    	for(int i=b[idx].l;i<=b[idx].r;i++)v[idx].push_back(a[i]);
    	sort(v[idx].begin(),v[idx].end());
    }
    void modify(int l,int r,int val){
    	int x=bl[l],y=bl[r];
    	if(x==y){
    		for(int i=l;i<=r;i++)a[i]+=val;
    		rebuild(x);
    	}else{
    		for(int i=x+1;i<=y-1;i++)b[i].add+=val;
    		for(int i=l;i<=b[x].r;i++)a[i]+=val;
    		for(int i=b[y].l;i<=r;i++)a[i]+=val;
    		rebuild(x),rebuild(y);
    	}
    }
    int query(int l,int r,int val){
    	int ans=0,x=bl[l],y=bl[r];
    	if(x==y){
    		for(int i=l;i<=r;i++)if(a[i]<val-b[x].add)++ans;
    	}else{
    		for(int i=x+1;i<=y-1;i++)ans+=lower_bound(v[i].begin(),v[i].end(),val-b[i].add)-v[i].begin();
    		for(int i=l;i<=b[x].r;i++)if(a[i]<val-b[x].add)++ans;
    		for(int i=b[y].l;i<=r;i++)if(a[i]<val-b[y].add)++ans;
    	}
    	return ans;
    }
    
    int main(){
    	n=m=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	make_block();
    	while(m--){
    		int opt=read(),l=read(),r=read(),val=read();
    		if(opt==0)modify(l,r,val);
    		else if(opt==1)printf("%d
    ",query(l,r,val*val));
    	}
    	return 0;
    }
    
  • 相关阅读:
    C#性能优化实践
    JavaScript类型转换
    JSON基础
    EasyUI DataGrid 内部input的事件
    WPF之Binding基础二 控件作为Binding的数据源
    WPF之Binding基础一 UI Binding Source
    JavaScript里面的“类”
    SqlServer随笔
    对象和类型
    浅谈类
  • 原文地址:https://www.cnblogs.com/wzj-xhjbk/p/9960137.html
Copyright © 2011-2022 走看看