zoukankan      html  css  js  c++  java
  • chef and churu 分块 好题

    题目大意

    有一个长度为n的数组A
    有n个函数,第i个函数 $$f(l[i],r[i])=sum_{k=l[i]}^{r[i]}A_k$$
    有两种操作:
    1)修改A[i]
    2)询问第x-y个函数值的和。
    数据范围:n<=100000

    分析1

    考虑询问时x=y的情况
    如何用尽可能快的速度回答询问?
    维护(sum1[i])表示前i块的前缀和
    维护(sum2[i][j])表示第i块中的前j个数的前缀和
    修改时暴力维护(sum2),接着暴力维护(sum1)
    复杂度(O(2*sqrt n))
    询问就可以(O(1))

    分析2

    如何结局区间函数询问呢
    我们对函数也分块
    维护(all[i])表示第i块函数的值
    维护(cov[i][j])表示第(i)块中,有多少个函数包含(A[j])
    对于(cov)数组,它是不会改变的
    预处理时对于每块扫一次
    用差分+前缀和的方法做到(O(nsqrt n))
    对于(all)
    每次修改时扫一下(sqrt n)个块,用(cov)数组看下修改的那个单点对这个块的(all)的影响

    注意

    别再把BL,BR写成x,y了好嘛?

    solution

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int M=100007;
    const int N=320;
    typedef unsigned long long LL;
    
    inline int rd(){
    	int x=0;bool f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(;isdigit(c);c=getchar()) x=x*10+c-48;
    	return f?x:-x;
    }
    
    int n,m,sn,MX;
    LL val[M];
    struct node{int l,r;}q[M];
    
    LL sum1[N];
    LL sum2[N][N];
    LL cov[N][M];
    LL all[N];
    
    int loc(int x){
    	return x/sn+1;
    }
    
    int getL(int x){
    	return max((x-1)*sn,1);
    }
    
    int getR(int x){
    	return min(x*sn-1,n);
    }
    
    int getP(int x){
    	int L=getL(loc(x));
    	return x-L+1;
    }
    
    void init_sum(int x){
    	int i,L=getL(x),R=getR(x);
    	LL nw=0;
    	for(i=L;i<=R;i++){
    		nw+=val[i];
    		sum2[x][getP(i)]=nw;
    	}
    	sum2[x][sn]=nw;//这样方便
    	for(int i=x;i<=MX;i++) sum1[i]=sum1[i-1]+sum2[i][sn];
    }
    
    LL get_sum(int x,int y){
    	int L,R,BL,BR;
    	BL=loc(x); BR=loc(y);
    	if(BL+1>=BR){
    		if(BL==BR) return sum2[BL][getP(y)]-sum2[BL][getP(x)-1];
    		
    		return sum2[BR][getP(y)]-sum2[BL][getP(x)-1]+sum2[BL][sn];
    	}
    	else{
    		if(getL(BL)!=x) BL++;
    		if(getR(BR)!=y) BR--;
    		L=getL(BL); R=getR(BR);
    		LL res=sum1[BR]-sum1[BL-1];
    		if(R!=y) res+=sum2[BR+1][getP(y)];
    		if(L!=x) res+=sum2[BL-1][sn]-sum2[BL-1][getP(x)-1];
    		return res;
    	}
    }
    
    void init_cov(int x){
    	int L=getL(x),R=getR(x);
    	for(int i=L;i<=R;i++){
    		cov[x][q[i].l]++;
    		cov[x][q[i].r+1]--;
    		all[x]+=get_sum(q[i].l,q[i].r);
    	}
    	for(int i=1;i<=n;i++){
    		cov[x][i]+=cov[x][i-1];
    	}
    }
    
    int main(){
    	int i,kd,x,y,BL,BR,L,R;
    	n=rd();
    	sn=(int)sqrt(n);
    	MX=loc(n);
    	
    	for(i=1;i<=n;i++) val[i]=rd();
    	
    	for(i=1;i<=n;i++) q[i].l=rd(),q[i].r=rd();
    
    	for(i=1;i<=MX;i++) init_sum(i);	
    	for(i=1;i<=MX;i++) 
    		init_cov(i);
    
    	m=rd();
    	
    	while(m--){
    		kd=rd();
    		x=rd(),y=rd();
    		if(kd==1){
    			y-=val[x];
    			val[x]+=y;
    			init_sum(loc(x));
    			for(i=1;i<=MX;i++) all[i]+=cov[i][x]*y;
    		}
    		else{
    			LL ans=0;
    			BL=loc(x); BR=loc(y);
    			
    			if(BL+1>=BR){
    				for(i=x;i<=y;i++) ans+=get_sum(q[i].l,q[i].r);
    			}
    			else{
    				if(getL(BL)!=x) BL++;
    				if(getR(BR)!=y) BR--;
    				L=getL(BL); R=getR(BR);
    				for(i=BL;i<=BR;i++) ans+=all[i];
    				for(i=x;i<L;i++) ans+=get_sum(q[i].l,q[i].r);
    				for(i=y;i>R;i--) ans+=get_sum(q[i].l,q[i].r);
    			}
    			printf("%llu
    ",ans);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    JavaScript的离线存储——localStorage、sessionStorage以及cookie
    for循环中的异步处理(异步变同步)
    pc网站随鼠标滚动动态出现效果
    layui tab选项卡Hash地址的定位和跳转到指定tab栏
    scroll滚动监听实现animate返回顶部(有坑)
    Vue之使用elementUI的upload上传组件导入csv文件
    element+sortablejs插件实现拖拽排序效果
    超简单的jq图片上传
    取字符串中的汉字的俩种方式
    js获得url地址携带参数
  • 原文地址:https://www.cnblogs.com/acha/p/6438349.html
Copyright © 2011-2022 走看看