zoukankan      html  css  js  c++  java
  • 关于分块的个人理解(一)

      上周开始讲分块,然而和我想的不一样,大家都听得很懵13 --> 以至于我对于自己对于分块的理解产生了怀疑。

      结果自然是写一篇blog自我检验一下了啊。

      那么切入正题。

    分块

    简意

      将一段暴力很费事的区间拆分成数个小区间分开求解,并采取预处理的方式降低复杂度。

      这种算法真的是很好的啊。

      尤其是对于我们这种懒惰oier来说,简直就是福音啊。

    实现方法

      将一段长序列分成相同的块大小,事先将整块的数据完成整理。然后进行整散拆分,整块直接使用,散块暴力

      那么这又有什么无法理解的地方呢?我真的很不理解QAQ

      那么接下来我们采取例题的方式来更具象的理解一下吧。

     基础. luogu P3870

    题目描述:

      现有N(2 ≤ N ≤ 100000)盏灯排成一排,从左到右依次编号为:1,2,......,N。

      然后依次执行M(1 ≤ M ≤ 100000)项操作,操作分为两种:

      第一种操作指定一个区间[a, b],然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开)。

      第二种操作是指定一个区间[a, b],要求你输出这个区间内有多少盏灯是打开的。灯在初始时都是关着的。

    输入:

      第一行有两个整数N和M,分别表示灯的数目和操作的数目。

      接下来有M行,每行有三个整数,依次为:c, a, b。其中c表示操作的种类:

        当c的值为0时,表示是第一种操作。

        当c的值为1时表示是第二种操作。

      a和b则分别表示了操作区间的左右边界(1 ≤ a ≤ b ≤ N)。

    输出:

      每当遇到第二种操作时,输出一行,包含一个整数:此时在查询的区间中打开的灯的数目。

    样例输入:

    4 5
    0 1 2
    0 2 4
    1 2 3
    0 2 4
    1 1 4

    样例输出:

    1
    2

    解法:

      这种东西真的很显然了啊,我都说了是分块的裸题了啊QAQ

      我们在修改的时候对于散块直接暴力修改,整块把用来标记的数组异或一下 1 就行了,修改次数为偶数时灯自然就不变了啊。

      但这样的话不好查整块,所以需要维护一个ans[i],用于保存块内目前开着的灯的数量。

      散块修改的时候好维护,而整块修改的时候把用块的大小减去ans维护就行了。

      那么查询的时候自然也很显然了啊,散块暴力,整块ans。

    代码奉上:

      风格较丑,请见谅哈。

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #define rint register int
    #define maxn 200010
    using namespace std;
    
    inline int read() {
        int s=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){ch=getchar();if(ch=='-')f=-1;}
        while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
        return s*f;
    }
    
    int n,m,blo,o;
    int bl[maxn],v[maxn],t[maxn],atag[maxn],sum[maxn];
    int L[maxn],R[maxn];
    
    inline void change(int l,int r) {
        if(bl[l]==bl[r]) {
            for(rint i=l;i<=r;++i) {
                if(v[i]) {
                    v[i]=0;
                    --sum[bl[l]];
                }
                else {
                    v[i]=1;
                    ++sum[bl[l]];
                }
            } 
            return;
        }
        for(rint i=l;i<=R[bl[l]];++i) {
            if(v[i]) {
                v[i]=0;
                --sum[bl[l]]; 
            }
            else {
                v[i]=1;
                ++sum[bl[l]];
            }
        }
        for(rint i=L[bl[r]];i<=r;++i) {
            if(v[i]) {
                v[i]=0;
                --sum[bl[r]];
            }
            else {
                v[i]=1;
                ++sum[bl[r]];
            }
        }
        for(rint i=bl[l]+1;i<=bl[r]-1;++i) 
            atag[i]=1-atag[i];
    }
    
    inline int query(int l,int r) {
        int ans=0;
        if(bl[l]==bl[r]) {
            for(rint i=l;i<=r;++i) 
                if(v[i]^atag[bl[l]]) 
                    ++ans;
            return ans;
        }
        for(int i=l;i<=R[bl[l]];++i) 
            if(v[i]^atag[bl[l]]) 
                ++ans;
        for(int i=L[bl[r]];i<=r;++i) 
            if(v[i]^atag[bl[r]]) 
                ++ans;
        for(int i=bl[l]+1;i<=bl[r]-1;++i) {
            if(atag[i]) 
                ans+=(R[i]-L[i]+1)-sum[i];
            else 
                ans+=sum[i];
        }        
        return ans;
    }
    
    int main()
    {
        n=read();
        m=read();
        blo=sqrt(n);
        n%blo?(o=n/blo+1):(o=n/blo);
        for(rint i=1;i<=n;++i) {
            v[i]=0;
            bl[i]=(i-1)/blo+1;
            if(v[i]) 
                ++sum[bl[i]];
        }
        for(rint i=1;i<=o;++i) {
            L[i]=(i-1)*blo+1;
            R[i]=i*blo;
        }
        while(m--) {
            int p=read();
            int l=read();
            int r=read();
            if(p==0) 
                change(l,r);
            if(p==1) 
                cout<<query(l,r)<<endl;
        }
        return 0;
    } 

    如此这题就完了耶~

    此处有彩蛋哦~

      作为一个懒 的打题的人怎么能放过双倍经验呢??????

      P2846 [USACO08NOV]光开关Light Switching

      SP7259 LITE - Light Switching

    祝大家RP++!!

      

  • 相关阅读:
    ASP.NET Web开发框架之二 数据输入窗体
    针对HTML5的更新和Unobtrusive Validation
    框架:从MVC到开放API
    使用SSIS创建同步数据库数据任务
    MVC里的Filters
    类型构造器也称为静态构造器,类构造器,或类型初始化器
    铁道部新客票系统设计(二)
    深入浅出SQL Server中的死锁
    你所能用到的数据结构(一)
    python网络编程学习笔记(6):Web客户端访问
  • 原文地址:https://www.cnblogs.com/qxyzili--24/p/10895805.html
Copyright © 2011-2022 走看看