zoukankan      html  css  js  c++  java
  • 分块入门

    将长为n操作序列分成好几块

    设定每块大小为根号n,这样就把序列分为了n/根号n块

    对于每一块,整体处理,不能构成一块的,枚举处理

    比如线段树的4个基本操作

    4个数组,bl[]记录属于哪一块,a[]记录原值,sum_sum[]记录块内总和,sum_change[]记录这一块都怎么改

    单点查询i:直接输出a[i]

    单点修改(如果是加上某个数)i:既修改a[i],又要修改sum_sum[bl[i]]

    区间修改[l,r](整体加上x):分3步

                ① x所在块,但要注意是从l到min(l所在块的最后一个,y)

                    枚举,a[i]+x,sum_sum[bl[i]]+x

                ② x和y之间的块(不包括x,y所在块)

                    一次性更改整个快,既sum_change[bl[i]]+x

                ③ y所在块,但要注意前提是x和y不在同一块内,

                   枚举 a[i]+x,sum_sum[bl[i]]+x

    区间查询(求和):也是分3步 分步情况与上面一样,不在叙述

                 ① ans+=a[i]+sum_change[bl[i]]

                 ② ans+=sum_sum[i]+sum_change[i]*根号n

                 ③ ans+=a[i]+sum_change[bl[i]]

    即将答案分为2部分,中间在块内的、两边不能构成一块的

    以下3题练练手

    T1 http://codevs.cn/problem/1080/ 线段树练习  单点修改+区间查询

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define N 100001
    using namespace std;
    int n,m,t;
    int sum[350],a[N],bl[N];
    int query(int x,int y)
    {
        int cur=0;
        for(int i=x;i<=min(bl[x]*t,y);i++) cur+=a[i];
        for(int i=bl[x]+1;i<bl[y];i++) cur+=sum[i];
        if(bl[x]!=bl[y])
        for(int i=(bl[y]-1)*t+1;i<=y;i++) cur+=a[i];
        return cur; 
    }
    int main()
    {
        scanf("%d",&n);
        t=sqrt(n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            bl[i]=(i-1)/t+1;
            sum[bl[i]]+=a[i];
        }
        scanf("%d",&m);
        int x,y,z;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            if(x==1)
            {
                a[y]+=z;
                sum[bl[y]]+=z;
            }
            else printf("%d
    ",query(y,z));
        }
    }
    View Code

    T2 http://codevs.cn/problem/1081/ 线段树练习2  单点查询+区间修改

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define N 100001
    using namespace std;
    int n,m,t;
    int sum[350],a[N],bl[N];
    int main()
    {
        scanf("%d",&n);
        t=sqrt(n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            bl[i]=(i-1)/t+1;
        }
        scanf("%d",&m);
        int x,y,z,p;
        for(int k=1;k<=m;k++)
        {
            scanf("%d",&p);
            if(p==1)
            {
                scanf("%d%d%d",&x,&y,&z);
                for(int i=x;i<=min(y,bl[x]*t);i++) a[i]+=z;
                for(int i=bl[x]+1;i<bl[y];i++) sum[i]+=z;
                if(bl[x]!=bl[y])
                for(int i=(bl[y]-1)*t+1;i<=y;i++) a[i]+=z; 
            }
            else 
            {
                scanf("%d",&x);
                printf("%d
    ",a[x]+sum[bl[x]]);
            }
        }
    }
    View Code

    T3 http://codevs.cn/problem/1082/ 线段树练习3 区间修改+区间查询

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define N 200001
    using namespace std;
    int n,m,t,bl[N];
    long long sum_change[500],a[N],sum_sum[500];
    int main()
    {
        scanf("%d",&n);
        t=sqrt(n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            bl[i]=(i-1)/t+1;
            sum_sum[bl[i]]+=a[i];
        }
        scanf("%d",&m);
        int x,y,z,p;
        for(int k=1;k<=m;k++)
        {
            scanf("%d",&p);
            if(p==1)
            {
                scanf("%d%d%d",&x,&y,&z);
                for(int i=x;i<=min(y,bl[x]*t);i++) a[i]+=z,sum_sum[bl[i]]+=z;
                for(int i=bl[x]+1;i<bl[y];i++) sum_change[i]+=z;
                if(bl[x]!=bl[y])
                for(int i=(bl[y]-1)*t+1;i<=y;i++) a[i]+=z,sum_sum[bl[i]]+=z; 
            }
            else 
            {
                long long cur=0;
                scanf("%d%d",&x,&y);
                for(int i=x;i<=min(y,bl[x]*t);i++) cur+=a[i]+sum_change[bl[i]];
                for(int i=bl[x]+1;i<bl[y];i++) cur+=sum_sum[i]+sum_change[i]*t;
                if(bl[x]!=bl[y]) 
                for(int i=(bl[y]-1)*t+1;i<=y;i++) cur+=a[i]+sum_change[bl[i]];
                printf("%lld
    ",cur);
            }
        }
    }
    View Code
  • 相关阅读:
    文件操作相关utils
    读取excel工具utils
    下载EXCEL文件Utils
    日期操作utils
    常用的utils
    坐标系转换Utils
    C# vs2019 CS0006 编译器错误CS1704
    C# 控制台形式 owin 添加WebApi 和Swagger
    Windows 下 Redis服务自动停止 处理
    Dotfuscator 混淆C# .Net代码 netcore
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6552462.html
Copyright © 2011-2022 走看看