文章目录
分块算法:
用 b l o c k = n block=\sqrt n block=n表示块大小,用两个数组表示每块的头和尾,第i个位置表示那个位置用 ( i − 1 ) / b l o c k + 1 (i-1)/block+1 (i−1)/block+1
int blck = sqrt(n);
int t = n/block;
if(n%block) t++;
for(int i=1;i<=t;i++){
st[i] = (i-1)*block+1;
ed[i] = i*block;
}
ed[t]=n;///最后一个是n
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
}
辅助数组:
-
a [ i ] a[i] a[i]数组表示i位置的元素
-
用 s u m [ i ] sum[i] sum[i]表示第i块的区间和预处理初值
for(int i=1;i<=t;i++){
for(int j=st[i];j<=ed[i];j++){
sum[i]+=a[j];
}
}
- a d d [ i ] add[i] add[i]表示第i块的增减量。表示整个块都需要增加。
对[l,r]区间进行+d操作,两种选择:
-
如果是对一个整块那么我们对add[i]进行+d,sum 不变
-
如果不是整块,那么我们对sum数组进行操作。
区间修改
void change(int l,int r,int d){///分块是优雅的暴力
int p = pos[l],q=pos[r];
if(p==q){///属于同一块
for(int i=li<=r;i++) a[i]+=d;
sum[p]+=d*(r-l+1);
}else {///不属于同一块
for(int i=p+1;i<q;i++)add[i]+=d;///整块操作
for(int i=l;i<=ed[p];i++)a[i]+=d;///对左端进行操作
sum[p]+=d*(ed[p]-l);
for(int i=st[q];i<=r;i++) a[i]+=d;///对右端进行操作
sum[q]+=d*(r-st[q]);
}
}
区间查询
两种情况:
-
[l,r]在同一个块中,那么暴力加上[l,r]这些数,最后再加上(r-l+1)个add[i]。答案是 a n s = a [ l ] + a [ l + 1 ] + . . . . + a [ r ] + ( r − l + 1 ) ∗ a d d [ l ] ans=a[l]+a[l+1]+....+a[r]+(r-l+1)*add[l] ans=a[l]+a[l+1]+....+a[r]+(r−l+1)∗add[l]
-
[l,r]中间有其他块,那么中间块进行枚举,每个块的贡献是sum[i]+add[i]*block,对两端进行操作1。
ll ask(int l,int r){
int p=pos[l],q=pos[r];
ll ans=0;
if(p==q){
for(int i=l;i<=r;i++) ans+=a[i];
ans+=add[p]*(r-l+1);
}else {
for(int i=p+1;i<q;i++)ans+=sum[i]+add[i]*block;
for(int i=l;i<=ed[p];i++) ans+=a[i];
ans+=add[p]*(ed[p]-l+1);
for(int i=st[q];i<=r;i++) ans+=a[i];
ans+=add[q]*(r-st[q]+1);
}
复杂度分析:
每一次查询或者修改复杂度最大是 2 n \sqrt {2n} 2n,一共操作 m m m次复杂度是 m n m\sqrt n mn
练习题:
我们用分块来做,需要二分,那么就需要维护一个单调的序列。但是又不能破坏原本的序列,那么我们用一个新序列维护他的单调性即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 7;
int n,m;
int a[maxn],b[maxn],pos[maxn];
int st[maxn],ed[maxn],sum[maxn],add[maxn];
void fr(char &x)
{
x=0;while(x!='M'&&x!='A') x=getchar();
}
void build(){
int block=sqrt(n);
int t = n/block;
if(n%block) t++;
for(int i=1;i<=t;i++){
st[i]=(i-1)*block+1;
ed[i]=i*block;
}
ed[t]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
b[i]=a[i];
}
for(int i=1;i<=t;i++){
sort(b+st[i],b+ed[i]+1);
}
}
void change(int l,int r,int d){
int p=pos[l],q=pos[r];
if(p==q){
for(int i=l;i<=r;i++){
a[i]+=d;
}
for(int i=st[q];i<=ed[q];i++){
b[i]=a[i];
}
sort(b+st[q],b+ed[q]+1);
}else {
for(int i=l;i<=ed[p];i++) a[i]+=d;
for(int i=st[p];i<=ed[p];i++) b[i]=a[i];
sort(b+st[p],b+ed[p]+1);
for(int i=st[q];i<=r;i++) a[i]+=d;
for(int i=st[q];i<=ed[q];i++) b[i]=a[i];
sort(b+st[q],b+ed[q]+1);
for(int i=p+1;i<q;i++) add[i]+=d;
}
}
int query(int l,int r,int d){
int ans=0;
int p=pos[l],q=pos[r];
if(p==q) {
for(int i=l;i<=r;i++){
if(a[i]+add[p]>=d) ans++;
}
}else {
for(int i=l;i<=ed[p];i++) if(a[i]+add[p]>=d) ans++;
for(int i=st[q];i<=r;i++) if(a[i]+add[q]>=d) ans++;
for(int i=p+1;i<q;i++){
int lx=st[i],rx=ed[i];
int sum=0;
while(lx<=rx){
int mid=(lx+rx)/2;
if(b[mid]+add[i]>=d){
rx=mid-1;
sum=ed[i]-mid+1;
}else {
lx=mid+1;
}
}
ans+=sum;
}
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build();
while(m--){
char ch;
fr(ch);
int l,r,d;
scanf("%d%d%d",&l,&r,&d);
if(ch=='A'){
printf("%d\n",query(l,r,d));
}else {
change(l,r,d);
}
}
return 0;
}
数列分块入门1
区间加法+单点查询:前段时间学的树状数组,我直接用树状数组维护的
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
#define ll long long
#define x first
#define y second
#define pii pair<int ,int >
const int mod = 1e9 + 7;
ll qpow(ll a, ll b, ll p)
{
ll ans = 1;
while (b)
{
if(b & 1) ans = ans * a % p;
b >>= 1;
a = a * a % p;
}
return ans;
}
ll tree[maxn];
ll lowbit(ll x){
return x&(-x);
}
void update(ll pos,ll x){
while(pos<maxn){
tree[pos]+=x;
pos+=lowbit(pos);
}
}
ll query(ll pos){
ll ans=0;
while(pos>0){
ans+=tree[pos];
pos-=lowbit(pos);
}
return ans;
}
void solve()
{
ll n;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
ll x;
scanf("%lld",&x);
update(i,x);
update(i+1,-x);
}
for(int i=1;i<=n;i++){
ll op,l,r,c;
scanf("%lld%lld%lld%lld",&op,&l,&r,&c);
if(op==0){
update(l,c);
update(r+1,-c);
}else {
printf("%lld\n",query(r));
}
}
}
int main()
{
int t = 1;
//scanf("%d", &t);
while(t--)
{
solve();
}
return 0;
}
数列分块入门 2
区间加法+区间查询小于x的个数
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 7;
int n,m;
ll a[maxn],b[maxn],pos[maxn];
ll st[maxn],ed[maxn],sum[maxn],add[maxn];
void fr(char &x)
{
x=0;while(x!='0'&&x!='1') x=getchar();
}
void build(){
ll block=sqrt(n);
ll t = n/block;
if(n%block) t++;
for(int i=1;i<=t;i++){
st[i]=(i-1)*block+1;
ed[i]=i*block;
}
ed[t]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
b[i]=a[i];
}
for(int i=1;i<=t;i++){
sort(b+st[i],b+ed[i]+1);
}
}
void change(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
for(int i=l;i<=r;i++){
a[i]+=d;
}
for(int i=st[q];i<=ed[q];i++){
b[i]=a[i];
}
sort(b+st[q],b+ed[q]+1);
}else {
for(int i=l;i<=ed[p];i++) a[i]+=d;
for(int i=st[p];i<=ed[p];i++) b[i]=a[i];
sort(b+st[p],b+ed[p]+1);
for(int i=st[q];i<=r;i++) a[i]+=d;
for(int i=st[q];i<=ed[q];i++) b[i]=a[i];
sort(b+st[q],b+ed[q]+1);
for(int i=p+1;i<q;i++) add[i]+=d;
}
}
ll query(ll l,ll r,ll d){
ll ans=0;
ll p=pos[l],q=pos[r];
if(p==q) {
for(int i=l;i<=r;i++){
if(a[i]+add[p]<d) ans++;
}
}else {
for(int i=l;i<=ed[p];i++) if(a[i]+add[p]<d) ans++;
for(int i=st[q];i<=r;i++) if(a[i]+add[q]<d) ans++;
for(int i=p+1;i<q;i++){
ll lx=st[i],rx=ed[i];
ll sum=0;
while(lx<=rx){
ll mid=(lx+rx)/2;
if(b[mid]+add[i]<d){
lx=mid+1;
sum=mid-st[i]+1;
}else {
rx=mid-1;
}
}
ans+=sum;
}
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build();
m=n;
while(m--){
char ch;
fr(ch);
ll l,r,d;
scanf("%lld%lld%lld",&l,&r,&d);
if(ch=='1'){
printf("%lld\n",query(l,r,d*d));
}else {
change(l,r,d);
}
}
return 0;
}
数列分块入门 3
区间加法+区间找小于x的最大值
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 7;
int n,m;
ll a[maxn],b[maxn],pos[maxn];
ll st[maxn],ed[maxn],sum[maxn],add[maxn];
void fr(char &x)
{
x=0;while(x!='0'&&x!='1') x=getchar();
}
void build(){
ll block=sqrt(n);
ll t = n/block;
if(n%block) t++;
for(int i=1;i<=t;i++){
st[i]=(i-1)*block+1;
ed[i]=i*block;
}
ed[t]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
b[i]=a[i];
}
for(int i=1;i<=t;i++){
sort(b+st[i],b+ed[i]+1);
}
}
void change(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
for(int i=l;i<=r;i++){
a[i]+=d;
}
for(int i=st[q];i<=ed[q];i++){
b[i]=a[i];
}
sort(b+st[q],b+ed[q]+1);
}else {
for(int i=l;i<=ed[p];i++) a[i]+=d;
for(int i=st[p];i<=ed[p];i++) b[i]=a[i];
sort(b+st[p],b+ed[p]+1);
for(int i=st[q];i<=r;i++) a[i]+=d;
for(int i=st[q];i<=ed[q];i++) b[i]=a[i];
sort(b+st[q],b+ed[q]+1);
for(int i=p+1;i<q;i++) add[i]+=d;
}
}
ll query(ll l,ll r,ll d){
ll ans=-1;
ll p=pos[l],q=pos[r];
if(p==q) {
for(int i=l;i<=r;i++){
if(a[i]+add[p]<d) ans=max(ans,a[i]+add[p]);
}
}else {
for(int i=l;i<=ed[p];i++) if(a[i]+add[p]<d) ans=max(ans,a[i]+add[p]);
for(int i=st[q];i<=r;i++) if(a[i]+add[q]<d) ans=max(ans,a[i]+add[q]);
for(int i=p+1;i<q;i++){
ll lx=st[i],rx=ed[i];
ll sum=0;
while(lx<=rx){
ll mid=(lx+rx)/2;
if(b[mid]+add[i]<d){
lx=mid+1;
sum=mid;
}else {
rx=mid-1;
}
}
if(sum&&b[sum]+add[i]<d) ans=max(ans,b[sum]+add[i]);
}
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build();
m=n;
while(m--){
char ch;
fr(ch);
ll l,r,d;
scanf("%lld%lld%lld",&l,&r,&d);
if(ch=='1'){
printf("%lld\n",query(l,r,d));
}else {
change(l,r,d);
}
}
return 0;
}
数列分块入门 4
区间加法+区间求和
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 7;
int n,m;
ll a[maxn],pos[maxn];
ll st[maxn],ed[maxn],sum[maxn],add[maxn];
void fr(char &x)
{
x=0;while(x!='0'&&x!='1') x=getchar();
}
void build(){
ll block=sqrt(n);
ll t = n/block;
if(n%block) t++;
for(int i=1;i<=t;i++){
st[i]=(i-1)*block+1;
ed[i]=i*block;
}
ed[t]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
}
for(int i=1;i<=t;i++){
for(int j=st[i];j<=ed[i];j++){
sum[i]+=a[j];
}
}
}
void change(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
for(int i=l;i<=r;i++){
a[i]+=d;
}
sum[p]+=(r-l+1)*d;
}else {
for(int i=l;i<=ed[p];i++) a[i]+=d;
sum[p]+=d*(ed[p]-l+1);
for(int i=st[q];i<=r;i++) a[i]+=d;
sum[q]+=d*(r-st[q]+1);
for(int i=p+1;i<q;i++){
add[i]+=d;
}
}
}
ll query(ll l,ll r,ll d){
ll ans=0;
ll p=pos[l],q=pos[r];
if(p==q) {
for(int i=l;i<=r;i++){
ans=(ans+a[i]+d+1)%(d+1);
}
ans+=add[p]*(r-l+1)%(d+1);
ans%=(d+1);
}else {
for(int i=l;i<=ed[p];i++) ans=(ans+a[i]+d+1)%(d+1);
ans+=add[p]*(ed[p]-l+1)%(d+1);
ans%=(d+1);
for(int i=st[q];i<=r;i++) ans=(ans+a[i]+d+1)%(d+1);
ans+=add[q]*(r-st[q]+1)%(d+1);
ans%=(d+1);
for(int i=p+1;i<q;i++) ans=((ans+sum[i]+d+1)%(d+1)+add[i]*(ed[i]-st[i]+1)%(d+1)+(d+1))%(d+1);
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build();
m=n;
while(m--){
char ch;
fr(ch);
ll l,r,d;
scanf("%lld%lld%lld",&l,&r,&d);
if(ch=='1'){
printf("%lld\n",query(l,r,d));
}else {
change(l,r,d);
}
}
return 0;
}
数列分块入门 5
区间开方,区间求和。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 7;
int n,m;
ll a[maxn],pos[maxn];
ll st[maxn],ed[maxn],sum[maxn],add[maxn];
void fr(char &x)
{
x=0;while(x!='0'&&x!='1') x=getchar();
}
void build(){
ll block=sqrt(n);
ll t = n/block;
if(n%block) t++;
for(int i=1;i<=t;i++){
st[i]=(i-1)*block+1;
ed[i]=i*block;
}
ed[t]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
}
for(int i=1;i<=t;i++){
for(int j=st[i];j<=ed[i];j++){
sum[i]+=a[j];
}
}
}
void change(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
for(int i=l;i<=r;i++){
sum[p]-=a[i];
a[i]=sqrt(a[i]);
sum[p]+=a[i];
}
}else {
for(int i=l;i<=ed[p];i++) {
sum[p]-=a[i];
a[i]=sqrt(a[i]);
sum[p]+=a[i];
}
for(int i=st[q];i<=r;i++){
sum[q]-=a[i];
a[i]=sqrt(a[i]);
sum[q]+=a[i];
}
for(int i=p+1;i<q;i++){
if(add[i]==1) continue;
else {
bool flag=0;
for(int j=st[i];j<=ed[i];j++){
sum[i]-=a[j];
a[j]=sqrt(a[j]);
sum[i]+=a[j];
if(a[j]>1) flag=1;
}
if(!flag) add[i]=1;
}
}
}
}
ll query(ll l,ll r,ll d){
ll ans=0;
ll p=pos[l],q=pos[r];
if(p==q) {
for(int i=l;i<=r;i++){
ans+=a[i];
}
}else {
for(int i=l;i<=ed[p];i++)ans+=a[i];
for(int i=st[q];i<=r;i++)ans+=a[i];
for(int i=p+1;i<q;i++) ans+=sum[i];
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build();
m=n;
while(m--){
char ch;
fr(ch);
ll l,r,d;
scanf("%lld%lld%lld",&l,&r,&d);
if(ch=='1'){
printf("%lld\n",query(l,r,d));
}else {
change(l,r,d);
}
}
return 0;
}
数列分块入门 6
单点插入+单点询问
我们利vector进行分块储存,每次当一个vector种的元素数量大于20block重新对块进行分配。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 7;
int n,m;
ll a[maxn],pos[maxn];
ll st[maxn],ed[maxn];
vector<ll> v[maxn];
ll block,t;
void fr(char &x)
{
x=0;while(x!='0'&&x!='1') x=getchar();
}
void build(){
ll top=0;
for(int i=1;i<=m;++i){
for(int j=0;j<(ll)v[i].size();j++){
st[++top]=v[i][j];
}
v[i].clear();
}
int block2=sqrt(top);
for(int i=1;i<=top;i++){
int x=(i-1)/block2+1;
v[x].push_back(st[i]);
}
m=(top-1)/block+1;
}
void change(ll l,ll r,ll d){
ll now=1;
while(l>(ll)v[now].size()){
l-=(ll)v[now].size();
now++;
}
l--;
v[now].insert(v[now].begin()+l,r);
if((ll)v[now].size()>20*block) build();
}
int main()
{
scanf("%d",&n);
block=sqrt(n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
v[(i-1)/block+1].push_back(a[i]);
}
m=(n-1)/block+1;
while(n--){
char ch;
fr(ch);
ll l,r,d;
scanf("%lld%lld%lld",&l,&r,&d);
if(ch=='1'){
ll now=1;
while(r>(ll)v[now].size()){
r-=(ll)v[now].size();
now++;
}
r--;
printf("%lld\n",v[now][r]);
}else {
change(l,r,d);
}
}
return 0;
}
数列分块入门 7
区间乘法+区间加法+单点查询。
我们用过分块2可知维护区间加法,那么同时怎么维护区间加法和区间乘法那?
首先我们知道 ( a + b ) ∗ c = a ∗ c + b ∗ c (a+b)*c=a*c+b*c (a+b)∗c=a∗c+b∗c和 ( a ∗ b ) + c (a*b)+c (a∗b)+c
知道这个之后我们就知道优先级了,知道优先级之后就直接用维护区间加法的方式维护即可,就是计算顺序注意。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 7;
const int mod=10007;
int n,m;
ll a[maxn],pos[maxn];
ll st[maxn],ed[maxn];
ll add[maxn],mul[maxn];
ll block,t;
void fr(char &x)
{
x=0;while(x!='0'&&x!='1'&&x!='2') x=getchar();
}
void Add(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
for(int i=st[p];i<=ed[p];i++){
a[i]=(a[i]*mul[p]%mod+add[p]+mod)%mod;
if(i>=l&&i<=r) a[i]=(a[i]+d+mod)%mod;
}
}
else {
for(int i=st[p];i<=ed[p];i++){
a[i]=(a[i]*mul[p]%mod+add[p]+mod)%mod;
if(i>=l&&i<=r) a[i]=(a[i]+d+mod)%mod;
}
for(int i=st[q];i<=ed[q];i++){
a[i]=(a[i]*mul[q]%mod+add[q]+mod)%mod;
if(i>=l&&i<=r) a[i]=(a[i]+d+mod)%mod;
}
for(int i=p+1;i<q;++i){
add[i]=(add[i]+d+mod)%mod;
}
}
mul[p]=1;
add[p]=0;
mul[q]=1;
add[q]=0;
}
void Mul(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
for(int i=st[p];i<=ed[p];i++){
a[i]=(a[i]*mul[p]%mod+add[p])%mod;
if(i>=l&&i<=r) a[i]=(a[i]*d+mod)%mod;
}
}else {
for(int i=st[p];i<=ed[p];i++){
a[i]=(a[i]*mul[p]%mod+add[p])%mod;
if(i>=l&&i<=r) a[i]=(a[i]*d+mod)%mod;
}
for(int i=st[q];i<=ed[q];i++){
a[i]=(a[i]*mul[q]%mod+add[q])%mod;
if(i>=l&&i<=r) a[i]=(a[i]*d+mod)%mod;
}
for(int i=p+1;i<q;++i){
mul[i]=(mul[i]*d+mod)%mod;
add[i]=(add[i]*d+mod)%mod;
}
}
mul[p]=1;
add[p]=0;
mul[q]=1;
add[q]=0;
}
int main()
{
scanf("%d",&n);
block=sqrt(n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
a[i]%=mod;
pos[i]= (i-1)/block+1;
add[pos[i]]=0;
mul[pos[i]]=1;
}
for(int i=1;i<=pos[n];i++){
st[i]=(i-1)*block+1;
ed[i]=i*block;
}
ed[pos[n]]=n;
while(n--){
char ch;
fr(ch);
ll l,r,d;
scanf("%lld%lld%lld",&l,&r,&d);
d=d%mod;
if(ch=='0'){
Add(l,r,d);
}else if(ch=='1'){
Mul(l,r,d);
}else {
printf("%lld\n",(a[r]*mul[pos[r]]+add[pos[r]])%mod);
}
}
return 0;
}
数列分块入门 8
区间查询c区间修改C
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 7;
int n,m;
ll a[maxn],pos[maxn];
ll st[maxn],ed[maxn],sum[maxn],add[maxn];
ll dis[maxn],vis[maxn];
void fr(char &x)
{
x=0;while(x!='0'&&x!='1') x=getchar();
}
void build(){
ll block=sqrt(n);
ll t = n/block;
if(n%block) t++;
for(int i=1;i<=t;i++){
st[i]=(i-1)*block+1;
ed[i]=i*block;
dis[i]=1;
vis[i]=-1;
}
ed[t]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
}
}
void change(ll l,ll r,ll d){
ll p=pos[l],q=pos[r];
if(p==q){
if(dis[p]==vis[p]){
for(int i=st[p];i<=ed[p];i++){
a[i]=dis[p];
}
}
for(int i=l;i<=r;i++){
a[i]=d;
}
dis[p]=1;
vis[p]=-1;
}else {
if(dis[p]==vis[p]){
for(int i=st[p];i<=ed[p];i++){
a[i]=dis[p];
}
}
for(int i=l;i<=ed[p];i++) {
a[i]=d;
}
if(dis[q]==vis[q]){
for(int i=st[q];i<=ed[q];i++){
a[i]=dis[q];
}
}
for(int i=st[q];i<=r;i++){
a[i]=d;
}
dis[p]=1;
vis[p]=-1;
dis[q]=1;
vis[q]=-1;
for(int i=p+1;i<q;i++){
dis[i]=vis[i]=d;
}
}
}
ll query(ll l,ll r,ll d){
ll ans=0;
ll p=pos[l],q=pos[r];
if(p==q) {
if(dis[p]==vis[p]){
if(dis[p]==d)
return r-l+1;
else return 0;
}
for(int i=l;i<=r;i++){
if(a[i]==d) ans++;
}
return ans;
}else {
if(dis[p]==vis[p]){
if(dis[p]==d)
ans+=ed[p]-l+1;
else ans+=0;
}
else {
for(int i=l;i<=ed[p];i++){
if(a[i]==d) ans++;
}
}
if(dis[q]==vis[q]){
if(dis[q]==d)
ans+=r-st[q]+1;
else ans+=0;
}
else {
for(int i=st[q];i<=r;i++){
if(a[i]==d) ans++;
}
}
for(int i=p+1;i<q;i++) {
if(dis[i]==vis[i]){
if(dis[i]==d) ans+=(ed[i]-st[i]+1);
}else {
for(int j=st[i];j<=ed[i];j++){
if(a[j]==d) ans++;
}
}
}
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build();
m=n;
while(m--){
//char ch;
//fr(ch);
ll l,r,d;
scanf("%lld%lld%lld",&l,&r,&d);
printf("%lld\n",query(l,r,d));
change(l,r,d);
}
return 0;
}
数列分块入门 9
区间最小众数
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5 + 7;
ll n, m, block;
ll a[maxn], b[maxn], pos[maxn], cnt[maxn], ans[maxn];
vector<ll> v[maxn];
map<ll, ll>mp;
ll dp[510][510];
void change(ll x)
{
memset(cnt, 0, sizeof cnt);
ll maxx = 0, num = 0;
for(int i = (x - 1) * block + 1; i <= n; i++)
{
ll c = ++cnt[a[i]];
if(c > num || c == num && b[a[i]] < b[maxx])
{
maxx = a[i];
num = c;
}
dp[x][pos[i]] = maxx;
}
}
ll alonf(ll l, ll r, ll x)
{
return upper_bound(v[x].begin(), v[x].end(), r) - lower_bound(v[x].begin(), v[x].end(), l);
}
ll query(ll l, ll r)
{
ll ans=0,num=0;
ll p = pos[l], q = pos[r];
ans = dp[p + 1][q - 1];
num = alonf(l, r, ans);
for(int i = l; i <= min(r, p * block); i++)
{
ll c = alonf(l, r, a[i]);
if(c > num || c == num && b[a[i]] < b[ans])
{
ans = a[i];
num = c;
}
}
if(p != q)
{
for(int i = (q - 1) * block + 1; i <= r; i++)
{
ll c = alonf(l, r, a[i]);
if(c > num || c == num && b[a[i]] < b[ans])
{
ans = a[i];
num = c;
}
}
}
return ans;
}
int main()
{
scanf("%lld", &n);
m = n;
block = sqrt(n);
ll idx = 0;
for(ll i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
pos[i] = (i - 1) / block + 1;
if(mp[a[i]] == 0)
{
mp[a[i]] = ++idx;
b[idx] = a[i];
}
a[i] = mp[a[i]];
v[a[i]].push_back(i);
}
for(ll i = 1; i <= pos[n]; i++) change(i);
while(m--)
{
ll l, r;
scanf("%lld%lld", &l, &r);
if(l > r) swap(l, r);
printf("%lld\n", b[query(l, r)]);
}
return 0;
}