zoukankan      html  css  js  c++  java
  • 分块学习

    分块是一种非常常用的技巧,他功能非常强大;然而相对的,它的时间复杂度较高,这也是它的缺陷。

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

    对于每一块,整体处理,不能构成一块的,暴力处理

    代码:

        for(int i=1;i<=n;i++)
        {
            a[i]=read();belong[i]=(i-1)/t+1;
            sum[belong[i]]+=a[i];
        } 

    这样就完成了分块 例如10个数,belong[i]分别为 1 1 1 2 2 2 3 3 3 4

    修改或查询时分三段区间

    1. L~min(belong[L],R),闭区间。

    2. belong[L]+1~belong[R],半开半闭区间。

    3.(belong[R]-1)*t+1~t,闭区间。

    这样就OK啦 例如区间求和

    代码:

    int query(int x,int y)
    {
        ans=0;
        for(int i=x;i<=min(y,belong[x]*t);i++) ans+=a[i];
        for(int i=belong[x]+1;i<belong[y];i++) ans+=sum[i];
        if(belong[x]!=belong[y]) for(int i=(belong[y]-1)*t+1;i<=y;i++) ans+=a[i];
        return ans;
    }

    以下3题练练手

    T1 http://codevs.cn/problem/1080/ 线段树练习  

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    #define N 100001
    
    using namespace std;
    int n,m,x,y,z,t,ans,a[N],belong[N],sum[N];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int query(int x,int y)
    {
        ans=0;
        for(int i=x;i<=min(y,belong[x]*t);i++) ans+=a[i];
        for(int i=belong[x]+1;i<belong[y];i++) ans+=sum[i];
        if(belong[x]!=belong[y]) for(int i=(belong[y]-1)*t+1;i<=y;i++) ans+=a[i];
        return ans;
    }
    
    int main()
    {
        n=read();t=sqrt(n);
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
            belong[i]=(i-1)/t+1;
            sum[belong[i]]+=a[i];
        }
        m=read();
        for(int i=1;i<=m;i++)
        {
            x=read();y=read();z=read();
            if(x==1){a[y]+=z;sum[belong[y]]+=z;}
            if(x==2){printf("%d
    ",query(y,z));}
        }
        return 0;
    }
    单点修改,区间查询

    T2 http://codevs.cn/problem/1081/ 线段树练习2

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    #define N 100001
    
    using namespace std;
    int n,m,q,x,y,z,t,ans,a[N],belong[N],tot[N];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int main()
    {
        n=read();t=sqrt(n);
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
            belong[i]=(i-1)/t+1;
        }
        m=read();
        for(int i=1;i<=m;i++)
        {
            x=read();
            if(x==1)
            {
                y=read();z=read();q=read();
                for(int i=y;i<=min(z,belong[y]*t);i++) a[i]+=q;
                for(int i=belong[y]+1;i<belong[z];i++) tot[i]+=q;
                if(belong[y]!=belong[z])for(int i=(belong[z]-1)*t+1;i<=z;i++) a[i]+=q;
            }
            if(x==2)
            {
                y=read();
                printf("%d
    ",a[y]+tot[belong[y]]);
            }
        }
        return 0;
    }
    单点查询,区间修改

    T3 http://codevs.cn/problem/1082/ 线段树练习3 

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    #define N 200001
    
    using namespace std;
    long long n,m,x,y,z,t,w,R;
    long long sum[N],flag[N],ans,a[N],belong[N];
    
    inline long long read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int main()
    {
        n=read();t=sqrt(n); 
        for(int i=1;i<=n;i++)
        {
            a[i]=read();belong[i]=(i-1)/t+1;
            sum[belong[i]]+=a[i];
        } 
        m=read();
        for(int i=1;i<=m;i++)
        {
            w=read();
            if(w==1)
            {
                x=read();y=read();z=read();R=min(y,belong[x]*t);
                for(int i=x;i<=R;i++) a[i]+=z,sum[belong[i]]+=z;
                for(int i=belong[x]+1;i<belong[y];i++) flag[i]+=z;
                if(belong[x]!=belong[y]) 
                for(int i=(belong[y]-1)*t+1;i<=y;i++) a[i]+=z,sum[belong[i]]+=z;
            }
            else
            {
                ans=0;
                x=read();y=read();R=min(y,belong[x]*t);
                for(int i=x;i<=R;i++) ans+=a[i]+flag[belong[i]];
                for(int i=belong[x]+1;i<belong[y];i++) ans+=sum[i]+flag[i]*t;
                if(belong[x]!=belong[y]) 
                for(int i=(belong[y]-1)*t+1;i<=y;i++) ans+=a[i]+flag[belong[i]];
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }
    区间修改+区间查询
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    Grails笔记二:grails 2.4.3版本下generate-*失效问题解析
    java常量池中基本数据类型包装类的小陷阱
    Mysql中使用聚合函数对null值的处理
    集合框架
    List的三个子类ArrayList,LinkedList,Vector之面试题
    String类面试题2
    String类常见面试题1
    常见对象之String类
    Scanner的概述和方法介绍
    Java开发工具(Eclipse工作空间的基本配置)
  • 原文地址:https://www.cnblogs.com/L-Memory/p/6939651.html
Copyright © 2011-2022 走看看