zoukankan      html  css  js  c++  java
  • 专题总结(分块)

    https://www.zybuluo.com/ysner/note/1290572

    思想

    把序列分成几块,然后整块整块地维护、处理信息。
    (tag):

    • 用空间换时间。
    • 复杂度永远带根号。

    模板

    就是(hzwer)大佬的分块(9)题。
    肛了(12h)。。。

    [loj6277]数列分块入门1

    注意块的边界问题:

    • 单独处理左端块时要对(r)(min)
    • 特判左右端点在同一块的情况。

    还有记住块的左端点为((bl[x]-1)*m+1),右端点为(bl[x]*m)

    https://new.loj.ac/submission/207033

    [loj6278]数列分块入门2

    一开始没有想到在块内排序和二分。

    如果要排序,每块就需要专门开(vector)存了。。。。

    每次加完数后,要对边上的块进行重新排序。

    重置(min)(max)时记得加上标记。

    https://new.loj.ac/submission/207164

    [loj6279]数列分块入门3

    和上一道题没什么差别啊。
    我基本只改了(Query)函数。

    https://new.loj.ac/submission/207177

    [loj6280]数列分块入门4

    对每个块维护一下数字之和及加法懒标记即可。
    然而竟然挂了几次细节。。。(在代码里标记了一下)

    https://new.loj.ac/submission/208651

    [loj6281]数列分块入门5

    碰到里面数字全为(1)(0)的块,跳过即可。

    其实我曾经设想过,在对整个块开方时,同时对存下的块中最大元素开方,但不知道为什么不可行。(见注释)
    所以还是顺带扫一遍保险些。

    https://new.loj.ac/submission/207274

    [loj6282]数列分块入门 6

    每次把数插到块里去。如果块过大,复杂度不能保证,就对所有数重新分块。

    另外,(vector)中有个能把数插进序列的函数(insert(pos,w))(pos)指指针位置,(w)为插入的数。
    这个函数让整个题变得非常暴力。。。

    https://new.loj.ac/submission/207363

    [loj6283]数列分块入门7

    有点类似线段树操作。
    给各块打上加法懒标记和乘法懒标记。
    对区间中的边角块,先下放标记再暴力更新值。

    https://new.loj.ac/submission/207496

    [loj6284]数列分块入门8

    这道题有点妙。
    注意到每次询问区间都挺大,所以在后期很多块中都会有数字相同的情况。
    于是对每个块维护表示块内数字是否相同的标记,不相同再到块里暴力修改和统计答案,相同就修改那个标记即可。
    在查询边角块前必须下放标记。
    https://new.loj.ac/submission/207958

    [loj6285]数列分块入门9

    想想查询一个区间的众数时会出现什么情况。
    一个区间包含三种块,左端点块(块(1)),右端点块(块(2))和其它在区间内的块(块(3)) 。
    很显然的是,在块(2)中不是众数的数,在经过块(1)和块(3)的补充后,可以变成众数。
    所以区间众数有三种可能:块(1)(3)中出现的数,及块(2)的众数。

    (2)的信息显然需要快速查询。
    于是我们要维护几个连续块的众数,及各数字出现的次数。
    这些东西都可以在(O(nsqrt n))的时间内预处理出来。(枚举从哪一个块开始)

    然后在询问中,暴力统计块(1)和块(3)中出现的数的出现次数即可。这个最高复杂度(O(2sqrt n))

    于是这个问题在(O(nsqrt n))时间复杂度内得到了解决。

    https://new.loj.ac/submission/207574

    考试题

    2018.9.20街灯

    给一个数列({a}),每次给出(l,r,p,v),询问一个区间内模(p)等于(v)的数有多少个。

    • (nleq10^5,qleq10^5,pleq10^9,a_ileq10^4)

    这个显然只能分块做。但是和上面的不太一样。
    实际上(pleq10^4)
    我们先预处理出(pleq100)时所有答案(以前缀和的形式)。
    然后处理出数字出现次数的前缀和。
    每次询问,(pleq100)直接(O(1))回答,否则暴力枚举(i*p+v)来统计答案,这里复杂度只有(O(sqrt n))(所以分块就是用来优化暴力的)。
    答案都是前缀和相减的形式。

    时间复杂度(O(nsqrt n))

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #define ll long long
    #define re register
    #define il inline
    #define pb(a) push_back(a)
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int N=1e5+100;
    int A[N],n,m,f[105][105],t[10005];
    struct que{int l,r,p,v,ans;}a[N];
    vector<int>q[N];
    il ll gi()
    {
      re ll x=0,t=1;
      re char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    int main()
    {
      n=gi();m=gi();
      fp(i,1,n) A[i]=gi();
      fp(i,1,m)
        {
          a[i].l=gi();a[i].r=gi();a[i].p=gi();a[i].v=gi();a[i].ans=0;
          q[a[i].l-1].pb(i);q[a[i].r].pb(i);
        }
      fp(i,1,n)
        {
          ++t[A[i]];
          fp(j,1,100) ++f[j][A[i]%j];
          for(re int j=0;j<q[i].size();j++)
    	{
    	  re int id=q[i][j],gu=(i==a[id].r)?1:-1,p=a[id].p,v=a[id].v;
    	  if(p<=100) a[id].ans+=gu*f[p][v];
    	  else
    	    for(re int i=0;i*p+v<=10000;i++)
    	      a[id].ans+=gu*t[i*p+v];
    	}
        }
      fp(i,1,m) printf("%d
    ",a[i].ans);
      fclose(stdin);
      fclose(stdout);
      return 0;
    }
    
  • 相关阅读:
    无名信号量在多线程间的同步
    ftok函数例子
    strerror和perror函数详解
    lockf函数的使用
    背包问题-2动态规划【正解】
    递归思想即背包问题
    生产者消费者问题(基于线程和无名信号量)
    eclipse 安装python后pydev不出现
    Eclipse+pydev解决中文显示和注释问题的方法大全
    MyEclipse10配置PyDev进行Python开发
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9696317.html
Copyright © 2011-2022 走看看