@ysner
2018-09-27T00:37:43.000000Z
字数 2672
阅读 2090
分块
总结
把序列分成几块,然后整块整块地维护、处理信息。
:
就是大佬的分块题。
肛了。。。
注意块的边界问题:
还有记住块的左端点为,右端点为
https://new.loj.ac/submission/207033
一开始没有想到在块内排序和二分。
如果要排序,每块就需要专门开存了。。。。
每次加完数后,要对边上的块进行重新排序。
重置和时记得加上标记。
https://new.loj.ac/submission/207164
和上一道题没什么差别啊。
我基本只改了函数。
https://new.loj.ac/submission/207177
对每个块维护一下数字之和及加法懒标记即可。
然而竟然挂了几次细节。。。(在代码里标记了一下)
https://new.loj.ac/submission/208651
碰到里面数字全为或的块,跳过即可。
其实我曾经设想过,在对整个块开方时,同时对存下的块中最大元素开方,但不知道为什么不可行。(见注释)
所以还是顺带扫一遍保险些。
https://new.loj.ac/submission/207274
每次把数插到块里去。如果块过大,复杂度不能保证,就对所有数重新分块。
另外,中有个能把数插进序列的函数,指指针位置,为插入的数。
这个函数让整个题变得非常暴力。。。
https://new.loj.ac/submission/207363
有点类似线段树操作。
给各块打上加法懒标记和乘法懒标记。
对区间中的边角块,先下放标记再暴力更新值。
https://new.loj.ac/submission/207496
这道题有点妙。
注意到每次询问区间都挺大,所以在后期很多块中都会有数字相同的情况。
于是对每个块维护表示块内数字是否相同的标记,不相同再到块里暴力修改和统计答案,相同就修改那个标记即可。
在查询边角块前必须下放标记。
https://new.loj.ac/submission/207958
想想查询一个区间的众数时会出现什么情况。
一个区间包含三种块,左端点块(块),右端点块(块)和其它在区间内的块(块) 。
很显然的是,在块中不是众数的数,在经过块和块的补充后,可以变成众数。
所以区间众数有三种可能:块、中出现的数,及块的众数。
块的信息显然需要快速查询。
于是我们要维护几个连续块的众数,及各数字出现的次数。
这些东西都可以在的时间内预处理出来。(枚举从哪一个块开始)
然后在询问中,暴力统计块和块中出现的数的出现次数即可。这个最高复杂度。
于是这个问题在时间复杂度内得到了解决。
https://new.loj.ac/submission/207574
给一个数列,每次给出,询问一个区间内模等于的数有多少个。
这个显然只能分块做。但是和上面的不太一样。
实际上。
我们先预处理出时所有答案(以前缀和的形式)。
然后处理出数字出现次数的前缀和。
每次询问,直接回答,否则暴力枚举来统计答案,这里复杂度只有(所以分块就是用来优化暴力的)。
答案都是前缀和相减的形式。
时间复杂度。
#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\n",a[i].ans);
fclose(stdin);
fclose(stdout);
return 0;
}