• 【XSY2111】Chef and Churus 分块 树状数组


    题目描述

      有一个长度为(n)的数组(A)(n)个区间([l_i,r_i]),有(q)次操作:

       (1~x~y):把(a_x)改成(y)

       (2~x~y):求第(l)个区间到第(r)个区间的区间和的和。

      (n,qleq {10}^5,a_ileq {10}^9)

    题解

      分块。

      设(s_i)为第(i)块的所有区间的区间和,(d_{i,j})为第(i)块有多少个区间包含了(j)这个位置。

      修改时修改树状数组和每个区间的区间和。设当前(a_x=v),则(s_i+=(y-v) imes d_{i,x})

      查询时完整的区间直接查询区间和,不完整的区间就暴力查询。

      设块大小为(m),时间复杂度为

    [T(n)=O(frac{n}{m}+mlog n) ]

      当(m=sqrt{frac{n}{log n}})

    [T(n)_{min}=O(nsqrt{nlog n}) ]

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    ull c[100010];
    int a[100010];
    int n;
    void add(int x,ull v)
    {
    	for(;x<=n;x+=x&-x)
    		c[x]+=v;
    }
    ull sum(int x)
    {
    	ull s=0;
    	for(;x;x-=x&-x)
    		s+=c[x];
    	return s;
    }
    int bl;
    ull s[1010];
    int d[1010][100010];
    int l[100010];
    int r[100010];
    int block[100010];
    int left[100010];
    int right[100010];
    int main()
    {
    	memset(c,0,sizeof c);
    //	freopen("xsy2111.in","r",stdin);
    //	freopen("xsy2111.out","w",stdout);
    	int m;
    	scanf("%d",&n);
    	int i;
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		add(i,a[i]);
    	}
    	bl=100;
    	m=(n+bl-1)/bl;
    	for(i=1;i<=n;i++)
    		block[i]=(i+bl-1)/bl;
    	for(i=1;i<=m;i++)
    	{
    		left[i]=(i-1)*bl+1;
    		right[i]=min(i*bl,n);
    	}
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d%d",&l[i],&r[i]);
    		s[block[i]]+=sum(r[i])-sum(l[i]-1);
    		d[block[i]][l[i]]++;
    		if(r[i]<n)
    			d[block[i]][r[i]+1]--;
    	}
    	int j;
    	for(i=1;i<=m;i++)
    		for(j=2;j<=n;j++)
    			d[i][j]+=d[i][j-1];
    	int q;
    	scanf("%d",&q);
    	int op,x,y,k;
    	for(i=1;i<=q;i++)
    	{
    		scanf("%d%d%d",&op,&x,&y);
    		if(op==1)
    		{
    			int v=a[x];
    			for(j=1;j<=m;j++)
    				s[j]+=ull(y-v)*d[j][x];
    			add(x,y-v);
    			a[x]=y;
    		}
    		else
    		{
    			ull ans=0;
    			for(j=block[x];j<=block[y];j++)
    				if(left[j]>=x&&right[j]<=y)
    					ans+=s[j];
    				else
    				{
    					int mi=max(left[j],x);
    					int mx=min(right[j],y);
    					for(k=mi;k<=mx;k++)
    						ans+=sum(r[k])-sum(l[k]-1);
    				}
    			printf("%llu
    ",ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Block & 代理
    堆&栈, 内存分配
    ASI 的 使用
    iOS开发-清理缓存功能的实现
    iOS8是如何跳转系统设置页面
    键盘弹出获取高度
    http://www.jianshu.com/collection/9a22b04a9357
    IOS 字符串中去除特殊符号 stringByTrimmingCharactersInSet
    iOS 判断输入是否全是空格
    iOS AFN 请求封装方法
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8511326.html
Copyright © 2020-2023  润新知