【LOJ 数列分块入门系列 总结 】

前言

由于之前没有写过分块,所以找个专题来学习一下这种优雅的暴力,由于很多题犯了好多智障的失误,整套分块入门系列大概用了一天时间,总结下来就是暴力,需要思考的是能用最少的复杂度维护除分块之外的东西,以及维护块与块之间的关系。

模板

init 部分主要把每个块划分出来,求出左右边界,以及处理出每个元素所属于的块
int n,num,BLOCK,bel[maxn],L[maxn],R[maxn];
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK + (n%BLOCK!=0) ;
    for(int i=1;i<=num;i++)
    {
        int l = (i-1)*BLOCK+1;
        int r = min(l+BLOCK-1,n);  这里需要注意,对n取min
        L[i]=l,R[i]=r;
        for(int j=l;j<=r;j++) bel[j]=i;
    }
}

数列分块入门 1

数列分块入门1

题意

给出一个长为 n n n的数列,以及 n n n个操作,操作涉及区间加法,单点查值。
1 ≤ n ≤ 5 ∗ 1 0 4 1 \leq n \leq 5*10^4 1n5104

做法

分块基础题,对于每次修改中不是整块的部分,暴力加上,这部分的长度不超过 2 ∗ n 2* \sqrt n 2n

对于整块的部分,维护整块被加的值即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
int n,num,BLOCK,bel[maxn],L[maxn],R[maxn],sum[maxn],a[maxn];
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK + (n%BLOCK!=0) ;
    for(int i=1;i<=num;i++)
    {
        int l = (i-1)*BLOCK+1;
        int r = min(l+BLOCK-1,n);
        L[i]=l,R[i]=r;
        for(int j=l;j<=r;j++) bel[j]=i;
    }
}
void add(int l,int r,int val)
{
    int st = bel[l],en = bel[r];
    if(st==en)
    {
        for(int i=l;i<=r;i++) a[i]+=val;
        return ;
    }
    for(int i=l;i<=R[st];i++) a[i]+=val;
    for(int i=L[en];i<=r;i++) a[i]+=val;
    for(int i=st+1;i<=en-1;i++) sum[i]+=val;
    return ;
}
int ask(int pos)
{
    return sum[bel[pos]]+a[pos];
}
int main()
{
    //freopen("A.in","r",stdin);
    read(n);
    init();
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=n;i++)
    {
        int a,b,c,d;
        read(a);read(b);read(c);read(d);
        if(a==0) add(b,c,d);
        else printf("%d\n",ask(c));
    }
    return 0;
}

数列分块入门2

数列分块入门2

题意

给出一个长为 n n n的数列,以及 n n n个操作,操作涉及区间加法,询问区间内小于某个值 x x x的元素个数。
1 ≤ n ≤ 5 ∗ 1 0 4 1 \leq n \leq 5*10^4 1n5104

做法

对每个块都维护一个有序的数组,这样每次在修改时,对于不是整块的部分,暴力修改并重新对那部分所在的块排序,由于这样的块不超过2,所以单次修改复杂度为 n × l o g ( n ) \sqrt n \times log(\sqrt n) n ×log(n ),对于整块的部分,维护一个整块被加的值即可。每次查询的时候,对于不是整块的部分,暴力统计,整块的部分lower_bound查询即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    inline void read(long long  &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
int n,num,BLOCK,bel[maxn],L[maxn],R[maxn];
ll a[maxn],b[maxn],sum[maxn];
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK + (n%BLOCK!=0);
    for(int i=1;i<=n;i++) b[i]=a[i];
    for(int i=1;i<=num;i++)
    {
        int l=(i-1)*BLOCK+1;
        int r=min(n,l+BLOCK-1);
        sort(b+l,b+1+r);
        L[i]=l,R[i]=r;
        for(int j=l;j<=r;j++) bel[j]=i;
    }
}
void add(int l,int r,int val)
{
    int st = bel[l], en = bel[r];
    if(st==en)
    {
        for(int i=l;i<=r;i++) a[i]+=val;
        for(int i=L[st];i<=R[st];i++) b[i]=a[i];
        sort(b+L[st],b+1+R[st]);
        return ;
    }
    for(int i=l;i<=R[st];i++) a[i]+=val;
    for(int i=L[st];i<=R[st];i++) b[i]=a[i];
    sort(b+L[st],b+1+R[st]);
    for(int i=L[en];i<=r;i++) a[i]+=val;
    for(int i=L[en];i<=R[en];i++) b[i]=a[i];
    sort(b+L[en],b+1+R[en]);
    for(int i=st+1;i<=en-1;i++) sum[i]+=val;
    return ;
}
int ask(int l,int r,int c)
{
    ll tt = 1LL*c*c;
    int st = bel[l], en = bel[r];
    int ans=0;
    if(st==en)
    {
        for(int i=l;i<=r;i++)
        {
            ans=ans+(a[i]+sum[st]<tt);
        }
        return ans;
    }
    for(int i=l;i<=R[st];i++) ans=ans+((a[i]+sum[st])<tt);
    for(int i=L[en];i<=r;i++) ans=ans+((a[i]+sum[en])<tt);
    for(int i=st+1;i<=en-1;i++)
    {
        int pos=lower_bound(b+L[i],b+1+R[i],tt-sum[i])-b;
        ans=ans+(pos-L[i]);
    }
    return ans;
}
int main()
{
    //freopen("B-3.in","r",stdin);
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    init();
    for(int i=1;i<=n;i++)
    {
        int op,l,r,d;
        read(op),read(l),read(r),read(d);
        if(op==0) add(l,r,d);
        else printf("%d\n",ask(l,r,d));
    }
    return 0;
}


数列分块入门3

数列分块入门3

题意

给出一个长为 n n n的数列,以及 n n n个操作,操作涉及区间加法,询问区间内小于某个值 x x x的前驱(比其小的最大元素)。

做法

对每个块都维护一个有序的数组,这样每次在修改时,对于不是整块的部分,暴力修改并重新对那部分所在的块排序,由于这样的块不超过2,所以单次修改复杂度为 n × l o g ( n ) \sqrt n \times log(\sqrt n) n ×log(n ),对于整块的部分,维护一个整块被加的值即可。每次查询的时候,对于不是整块的部分,暴力统计,整块的部分lower_bound查询即可,由于这道题目只查询值而不需要计数,所以每个块开一个set维护也可以。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    inline void read(long long  &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
int n,num,BLOCK,bel[maxn],L[maxn],R[maxn];
ll a[maxn],b[maxn],sum[maxn];
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK + (n%BLOCK!=0);
    for(int i=1;i<=n;i++) b[i]=a[i];
    for(int i=1;i<=num;i++)
    {
        int l=(i-1)*BLOCK+1;
        int r=min(n,l+BLOCK-1);
        sort(b+l,b+1+r);
        L[i]=l,R[i]=r;
        for(int j=l;j<=r;j++) bel[j]=i;
    }
}
void add(int l,int r,int val)
{
    int st = bel[l], en = bel[r];
    if(st==en)
    {
        for(int i=l;i<=r;i++) a[i]+=val;
        for(int i=L[st];i<=R[st];i++) b[i]=a[i];
        sort(b+L[st],b+1+R[st]);
        return ;
    }
    for(int i=l;i<=R[st];i++) a[i]+=val;
    for(int i=L[st];i<=R[st];i++) b[i]=a[i];
    sort(b+L[st],b+1+R[st]);
    for(int i=L[en];i<=r;i++) a[i]+=val;
    for(int i=L[en];i<=R[en];i++) b[i]=a[i];
    sort(b+L[en],b+1+R[en]);
    for(int i=st+1;i<=en-1;i++) sum[i]+=val;
    return ;
}
ll ask(int l,int r,int c)
{
    int st = bel[l], en = bel[r];
    ll ans=-1;
    if(st==en)
    {
        for(int i=l;i<=r;i++)
        {
            if(a[i]+sum[st]<c) ans=max(ans,a[i]+sum[st]);
        }
        return ans;
    }
    for(int i=l;i<=R[st];i++)
    {
        if(a[i]+sum[st]<c) ans=max(ans,a[i]+sum[st]);
    }
    for(int i=L[en];i<=r;i++)
    {
        if(a[i]+sum[en]<c) ans=max(ans,a[i]+sum[en]);
    }
    for(int i=st+1;i<=en-1;i++)
    {
        int pos=lower_bound(b+L[i],b+1+R[i],c-sum[i])-b;
        if(pos==L[i]) continue;
        else ans=max(ans,b[pos-1]+sum[i]);
    }
    return ans;
}
int main()
{
    //freopen("C.in","r",stdin);
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    init();
    for(int i=1;i<=n;i++)
    {
        int op,l,r,d;
        read(op),read(l),read(r),read(d);
        if(op==0) add(l,r,d);
        else printf("%lld\n",ask(l,r,d));
    }
    return 0;
}

数列分块入门4

数列分块入门4

题意

给出一个长为 n n n的数列,以及 n n n个操作,操作涉及区间加法,区间求和。

做法

对于不是整块的查询或修改,暴力即可,否则维护一个整块被加的值以及区间内元素个数即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    inline void read(long long  &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
int  n,BLOCK,num,L[maxn],R[maxn],bel[maxn];
ll sum[maxn],a[maxn],res[maxn];
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK + (n%BLOCK!=0);
    for(int i=1;i<=num;i++)
    {
        int l=(i-1)*BLOCK+1;
        int r=min(n,l+BLOCK-1);
        L[i]=l,R[i]=r;
        for(int j=l;j<=r;j++)
        {
            bel[j]=i;
            res[i]+=a[j];
        }
    }
}
void add(int l,int r,int val)
{
    int st = bel[l],en = bel[r];
    if(st==en)
    {
        for(int i=l;i<=r;i++)
        {
            a[i]+=val;
            res[st]+=val;
        }
        return ;
    }
    for(int i=l;i<=R[st];i++) a[i]+=val,res[st]+=val;
    for(int i=L[en];i<=r;i++) a[i]+=val,res[en]+=val;
    for(int i=st+1;i<=en-1;i++) sum[i]+=val;
}
ll ask(int l,int r,int val)
{
    val++;
    ll ans=0;
    int st=bel[l],en=bel[r];
    if(st==en)
    {
        for(int i=l;i<=r;i++) ans=(ans+(a[i]+sum[st])%val+val)%val;
        return ans;
    }
    for(int i=l;i<=R[st];i++) ans=(ans+(a[i]+sum[st])%val+val)%val;
    for(int i=L[en];i<=r;i++) ans=(ans+(a[i]+sum[en])%val+val)%val;
    for(int i=st+1;i<=en-1;i++) ans=(ans+(res[i]%val+val)%val+(sum[i]%val+val)%val*(R[i]-L[i]+1)%val)%val;
    return ans;
}
int main()
{
    //freopen("D.in","r",stdin);
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    init();
    for(int i=1;i<=n;i++)
    {
        int op,l,r,val;
        read(op),read(l),read(r),read(val);
        if(op==0) add(l,r,val);
        else printf("%lld\n",ask(l,r,val));
    }
    return 0;
}



数列分块入门5

数列分块入门5

题意

给出一个长为 n n n的数列 ,以及n个操作,操作涉及区间开方,区间求和。

做法

要用到一个性质,一个int之内的数字最多开五次根号向下取整就会变成1。所以我们只需要维护每个块内是否有大于1的元素即可。如果块内存在大于1的元素,暴力更新,否则就跳过这个块。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll ·   pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
int n,num,bel[maxn],L[maxn],R[maxn],a[maxn],flag[maxn],BLOCK;
ll sum[maxn];
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK+(n%BLOCK!=0);
    for(int i=1;i<=num;i++)
    {
        int l = (i-1)*BLOCK+1;
        int r = min(l+BLOCK-1,n);
        L[i]=l,R[i]=r;
        flag[i]=1;
        for(int j=l;j<=r;j++) bel[j]=i,sum[i]+=a[j];
    }
}
void sqr(int l,int r)
{
    int st=bel[l],en=bel[r];
    if(st==en)
    {
        for(int i=l;i<=r;i++) a[i]=sqrt(a[i]);
        flag[st]=0;
        sum[st]=0;
        for(int i=L[st];i<=R[st];i++) sum[st]+=a[i];
        for(int i=L[st];i<=R[st];i++) if(a[i]>1) flag[st]=1;
        return ;
    }
    for(int i=l;i<=R[st];i++) a[i]=sqrt(a[i]);
    flag[st]=0,sum[st]=0;
    for(int i=L[st];i<=R[st];i++) if(a[i]>1) flag[st]=1;
    for(int i=L[st];i<=R[st];i++) sum[st]+=a[i];
    for(int i=L[en];i<=r;i++) a[i]=sqrt(a[i]);
    flag[en]=0,sum[en]=0;
    for(int i=L[en];i<=R[en];i++) if(a[i]>1) flag[en]=1;
    for(int i=L[en];i<=R[en];i++) sum[en]+=a[i];
    for(int i=st+1;i<=en-1;i++)
    {
        if(flag[i]==0) continue;
        for(int j=L[i];j<=R[i];j++) a[j]=sqrt(a[j]);
        flag[i]=0,sum[i]=0;
        for(int j=L[i];j<=R[i];j++) if(a[j]>1) flag[i]=1;
        for(int j=L[i];j<=R[i];j++) sum[i]+=a[j];
    }
}
ll ask(int l,int r)
{
    int st=bel[l],en=bel[r];
    ll ans=0;
    if(st==en)
    {
        for(int i=l;i<=r;i++) ans=ans+a[i];
        return ans;
    }
    for(int i=l;i<=R[st];i++) ans=ans+a[i];
    for(int i=L[en];i<=r;i++) ans=ans+a[i];
    for(int i=st+1;i<=en-1;i++) ans=ans+sum[i];
    return ans;
}
int main()
{
    //freopen("E.in","r",stdin);
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    init();
    for(int i=1;i<=n;i++)
    {
        int op,l,r,val;
        read(op),read(l),read(r),read(val);
        if(op==0) sqr(l,r);
        else printf("%lld\n",ask(l,r));
    }
    return 0;
}


数列分块入门 6

数列分块入门6

题意

给出一个长为 n n n的数列,以及 n n n个操作,操作涉及单点插入,单点询问,数据随机生成。

做法

我的做法就是动态维护每个块所包含的元素信息,首先对每个块开一个双端队列,之后对于每次插入,只需要更改每个块内队头队尾两个元素,所以复杂度是 n \sqrt n n 的,对于每次查询直接返回即可。这种做法在更新的时候需要维护很多信息,应该有更优的做法。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<deque>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
int n,BLOCK,num,L[maxn],R[maxn],bel[maxn],a[maxn];
deque<int> d[maxn];
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK + (n%BLOCK!=0);
    for(int i=1;i<=num;i++)
    {
        int l=(i-1)*BLOCK+1;
        int r=l+BLOCK-1;
        L[i]=l,R[i]=r;
        for(int j=l;j<=r;j++)
        {
            bel[j]=i;
            d[i].push_back(a[j]);
        }
    }
}
void up(int pos,int val)
{
    int res = bel[pos];
    if(res==num)
    {
        if(R[res]-L[res]+1==BLOCK)
        {
            vector<int> tt;
            for(int i=0;i<pos-L[res];i++)  tt.push_back(d[res][i]);
            tt.push_back(val);
            for(int i=pos-L[res];i<d[res].size();i++) tt.push_back(d[res][i]);
            d[res].clear();
            for(int i=0;i<tt.size()-1;i++) d[res].push_back(tt[i]);
            num++;
            n++;
            L[num]=n;
            R[num]=n;
            bel[n]=num;
            d[num].push_back(tt.back());
        }
        else
        {
            vector<int> tt;
            for(int i=0;i<pos-L[res];i++)  tt.push_back(d[res][i]);
            tt.push_back(val);
            for(int i=pos-L[res];i<d[res].size();i++) tt.push_back(d[res][i]);
            d[res].clear();
            for(int i=0;i<tt.size();i++) d[res].push_back(tt[i]);
            for(int i=L[res];i<=R[res]+1;i++) bel[i]=res;
            R[res]++;
            n++;
        }
    }
    else
    {
        int pre=d[res].back();
        d[res].pop_back();
        vector<int> tt;
        for(int i=0;i<pos-L[res];i++)  tt.push_back(d[res][i]);
        tt.push_back(val);
        for(int i=pos-L[res];i<d[res].size();i++) tt.push_back(d[res][i]);
        d[res].clear();
        for(int i=0;i<tt.size();i++) d[res].push_back(tt[i]);
        for(int i=res+1;i<num;i++)
        {
            d[i].push_front(pre);
            pre=d[i].back();
            d[i].pop_back();
        }
        if(R[num]-L[num]+1==BLOCK)
        {
            d[num].push_front(pre);
            pre=d[num].back();
            d[num].pop_back();
            num++;
            n++;
            d[num].push_back(pre);
            L[num]=n,R[num]=n;
            bel[n]=num;
        }
        else
        {
            d[num].push_front(pre);
            n++;
            R[num]=n;
            bel[n]=num;
        }
    }
}
int ask(int pos)
{
    int res=bel[pos];
    return d[res][pos-L[res]];
}
int main()
{
    //freopen("F-2.in","r",stdin);
    int m;
    read(n);
    //read(m);
    m=n;
    for(int i=1;i<=n;i++) read(a[i]);
    init();
    for(int i=1;i<=m;i++)
    {
        int op,l,r,c;
        read(op),read(l),read(r),read(c);
        if(op==0) up(l,r);
        else printf("%d\n",ask(r));
    }
    return 0;
}

数列分块入门 7

数列分块入门7

题意

给出一个长为 n n n的数列,以及 n n n个操作,操作涉及区间乘法,区间加法,单点询问。

做法

我的做法比较麻烦,应该有更好的做法,对于每个块维护一个这样的信息,ans[i]=a[i]*MUL + ADD 。也就是对于每个块维护MUL和ADD这两个变量,最初MUL=1,ADD=0。

对于每次区间乘法操作,对于不是整块的部分,暴力更新,但是暴力更新之后仍要让他满足上面的式子,于是需要把更新变一个样子。设当前区间乘X。

相当于把a[i]*MUL+ADD整体乘X,也就是 ( a [ i ] × M U L + A D D ) × X (a[i] \times MUL + ADD) \times X (a[i]×MUL+ADD)×X

在不想改变MUL和ADD的情况下,需要这样改变一下

( a [ i ] × M U L + A D D ) × X (a[i] \times MUL+ADD) \times X (a[i]×MUL+ADD)×X

= a [ i ] × M U L × X + A D D × X a[i] \times MUL \times X + ADD \times X a[i]×MUL×X+ADD×X

= ( a [ i ] × X + A D D × X − A D D M U L ) × X + A D D (a[i]\times X + \frac{ADD\times X-ADD}{MUL})\times X + ADD (a[i]×X+MULADD×XADD)×X+ADD

也就是说对于每个非整块的a[i],我们只需要把 a [ i ] a[i] a[i]暴力更新成 a [ i ] × X + A D D × X − A D D M U L a[i]\times X + \frac{ADD\times X-ADD}{MUL} a[i]×X+MULADD×XADD即可。

对于整块的部分,我们分别修改MUL和ADD即可。

对于每次区间加法操作,对于不是整块的部分,也需要改变一下。

( a [ i ] × M U L + A D D ) + X (a[i] \times MUL+ADD) + X (a[i]×MUL+ADD)+X

= ( a [ i ] + X M U L ) × M U L + A D D (a[i]+\frac{X}{MUL})\times MUL + ADD (a[i]+MULX)×MUL+ADD

也就是说对于每个非整块的a[i],我们只需要把 a [ i ] a[i] a[i]暴力更新成 a [ i ] × X + A D D × X − A D D M U L a[i]\times X + \frac{ADD\times X-ADD}{MUL} a[i]×X+MULADD×XADD即可。

对于整块的部分,我们修改ADD的值即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 10007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
int n,BLOCK,num,L[maxn],R[maxn],bel[maxn],a[maxn],sum[maxn],mul[maxn],inv[maxn];
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK +(n%BLOCK!=0);
    for(int i=1;i<=num;i++)
    {
        int l=(i-1)*BLOCK+1;
        int r=l+BLOCK-1;
        L[i]=l,R[i]=r;
        mul[i]=1,sum[i]=0;
        for(int j=l;j<=r;j++) bel[j]=i;
    }
}
void add(int l,int r,int c)
{
    int st=bel[l],en=bel[r];
    if(st==en)
    {
        for(int i=l;i<=r;i++) a[i]=(a[i]+c*inv[mul[st]]%Mod)%Mod;
        return ;
    }
    for(int i=l;i<=R[st];i++) a[i]=(a[i]+c*inv[mul[st]]%Mod)%Mod;
    for(int i=L[en];i<=r;i++) a[i]=(a[i]+c*inv[mul[en]]%Mod)%Mod;
    for(int i=st+1;i<=en-1;i++) sum[i]=(sum[i]+c)%Mod;
}
void mulp(int l,int r,int c)
{
    int st=bel[l],en=bel[r];
    if(st==en)
    {
        for(int i=l;i<=r;i++) a[i] = (a[i]*c%Mod+sum[st]*c%Mod*inv[mul[st]]%Mod-sum[st]*inv[mul[st]]%Mod+Mod)%Mod;
        return ;
    }
    for(int i=l;i<=R[st];i++) a[i] = (a[i]*c%Mod+sum[st]*c%Mod*inv[mul[st]]%Mod-sum[st]*inv[mul[st]]%Mod+Mod)%Mod;
    for(int i=L[en];i<=r;i++) a[i] = (a[i]*c%Mod+sum[en]*c%Mod*inv[mul[en]]%Mod-sum[en]*inv[mul[en]]%Mod+Mod)%Mod;
    for(int i=st+1;i<=en-1;i++)
    {
        sum[i]=sum[i]*c%Mod;
        mul[i]=mul[i]*c%Mod;
        if(mul[i]==0)
        {
            for(int j=L[i];j<=R[i];j++) a[j]=sum[i];
            mul[i]=1;
            sum[i]=0;
        }
    }
}
int ask(int pos)
{
    int res=bel[pos];
    return (a[pos]*mul[res]%Mod+sum[res])%Mod;
}
ll pow_(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%Mod;
        b>>=1;
        a=a*a%Mod;
    }
    return ans;
}
int main()
{
    //freopen("a4.in","r",stdin);
    //freopen("a4.out","w",stdout);
    for(int i=1;i<=20000;i++) inv[i]=pow_(i,Mod-2);
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    init();
    for(int i=1;i<=n;i++)
    {
        int op,l,r,c;
        read(op),read(l),read(r),read(c);
        if(op==0) add(l,r,c);
        else if(op==1) mulp(l,r,c);
        else printf("%d\n",ask(r));
    }
    return 0;
}


数列分块入门 8

数列分块入门8

题意

给出一个长为 n n n的数列,以及 n n n个操作,操作涉及区间询问等于一个数 c c c的元素,并将这个区间的所有元素改为c。

做法

只需要维护一个块内的元素是否都相同即可,当不相同时暴力更新当前块,否则跳过。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
int n,num,a[maxn],bel[maxn],L[maxn],R[maxn],col[maxn],BLOCK;
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK + (n%BLOCK!=0);
    for(int i=1;i<=num;i++)
    {
        int l = (i-1)*BLOCK+1;
        int r = min(l + BLOCK - 1,n);
        L[i]=l,R[i]=r;
        for(int j=l;j<=r;j++) bel[j]=i;
        col[i]=a[l];
        for(int j=l;j<=r;j++) if(a[j]!=a[l]) col[i]=-1;
    }
}
int modify(int l,int r,int c)
{
    int st=bel[l],en=bel[r];
    int ans=0;
    if(st == en)
    {
        if(col[st]!=-1) for(int j=L[st];j<=R[st];j++) a[j] = col[st];
        for(int i=l;i<=r;i++)
        {
            if(col[st]==-1)
            {
                if(a[i]==c) ans++;
            }
            else if(col[st]==c) ans++;
            a[i]=c;
        }
        col[st]=c;
        for(int i=L[st];i<=R[st];i++) if(a[i]!=c) col[st]=-1;
        return ans;
    }
    if(col[st]!=-1) for(int j=L[st];j<=R[st];j++) a[j] = col[st];
    for(int i=l;i<=R[st];i++)
    {
        if(col[st]==-1)
        {
            if(a[i]==c) ans++;
        }
        else if(col[st]==c) ans++;
        a[i]=c;
    }
    col[st]=c;
    for(int i=L[st];i<=R[st];i++) if(a[i]!=c) col[st]=-1;
    if(col[en]!=-1) for(int j=L[en];j<=R[en];j++) a[j] = col[en];
    for(int i=L[en];i<=r;i++)
    {
        if(col[en]==-1)
        {
            if(a[i]==c) ans++;
        }
        else if(col[en]==c) ans++;
        a[i]=c;
    }
    col[en]=c;
    for(int i=L[en];i<=R[en];i++) if(a[i]!=c) col[en]=-1;
    for(int i=st+1;i<=en-1;i++)
    {
        if(col[i]!=-1)
        {
            if(col[i]==c) ans=ans+(R[i]-L[i]+1);
            else col[i]=c;
        }
        else
        {
            for(int j=L[i];j<=R[i];j++) if(a[j]==c) ans++;
            col[i]=c;
        }
    }
    return ans;
}
int main()
{
    //freopen("H.in","r",stdin);
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    init();
    for(int i=1;i<=n;i++)
    {
        int l,r,c;
        read(l),read(r),read(c);
        printf("%d\n",modify(l,r,c));
    }
    return 0;
}



数列分块入门 9

数列分块入门9

题意

给出一个长为 n n n的数列,以及 n n n个操作,操作涉及询问区间的最小众数。

做法

首先预处理出几个数组, d p [ i ] [ j ] dp[i][j] dp[i][j]表示第i个块到第j个块之间的最小众数的出现次数, d p 2 [ i ] [ j ] dp2[i][j] dp2[i][j]表示第i个块到第j个块之间的最小众数的值, p r e [ i ] [ j ] pre[i][j] pre[i][j]表示i这个数在前j个块中的出现次数,由于原数组值很大,需要离散化一下。

之后对于每次查询,我们先求出整数块内的最小众数,之后答案一定产生在前者或者非整数块的某个整数中。暴力统计非整数块每个整数在当前区间出现的次数即可,用之前预处理的数组可以做到复杂度 n \sqrt n n

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+10;
const int N = 800;
int n,BLOCK,num,bel[maxn],L[maxn],R[maxn],a[maxn],b[maxn],Hash[maxn],c[maxn],dp[N][N],dp2[N][N],um[maxn],pre[N][maxn],tmp[maxn],sum[maxn];
vector<int> v[maxn];
void GetHash(int a[],int n)
{
    for(int i=1;i<=n;i++) Hash[i]=a[i];
    sort(Hash+1,Hash+1+n);
    int d=unique(Hash+1,Hash+1+n)-Hash-1;
    for(int i=1;i<=n;i++)
    {
        b[i]=lower_bound(Hash+1,Hash+1+d,a[i])-Hash;
        c[b[i]]=a[i];
    }
}
void init()
{
    BLOCK = sqrt(n);
    num = n/BLOCK +(n%BLOCK!=0);
    for(int i=1;i<=n;i++)
    {
        int l=(i-1)*BLOCK+1;
        int r=min(l+BLOCK-1,n);
        L[i]=l,R[i]=r;
        for(int j=l;j<=r;j++) bel[j]=i;
    }
    for(int i=1;i<=num;i++)
    {
        for(int j=1;j<=n;j++) sum[j]=0;
        int ans=-1,res;
        for(int j=i;j<=num;j++)
        {
            for(int k=L[j];k<=R[j];k++)
            {
                if(++sum[b[k]]>ans)
                {
                    ans=sum[b[k]];
                    res=b[k];
                }
                else if(sum[b[k]]==ans&&b[k]<res) res=b[k];
            }
            dp2[i][j]=ans;
            dp[i][j]=res;
        }
    }
    for(int i=1;i<=n;i++) v[b[i]].push_back(i);
    for(int i=1;i<=num;i++)
    {
        for(int j=L[i];j<=R[i];j++) pre[i][b[j]]++;
        for(int j=1;j<=n;j++) pre[i][j]+=pre[i-1][j];
    }
}
int ask(int l,int r)
{
    int st=bel[l],en=bel[r];
    if(st==en)
    {
        int ans=-1,res;
        for(int i=l;i<=r;i++) tmp[b[i]]=0;
        for(int i=l;i<=r;i++)
        {
            int tt=++tmp[b[i]];
            if(tt>ans) ans=tt,res=b[i];
            else if(tt==ans&&b[i]<res) res=b[i];
        }
        return res;
    }
    int ans=-1,res;
    if(st+1<=en-1)
    {
        res=dp[st+1][en-1];
        ans=dp2[st+1][en-1];
        for(int i=l;i<=R[st];i++) if(b[i]==res) ans++;
        for(int i=L[en];i<=r;i++) if(b[i]==res) ans++;
    }
    for(int i=l;i<=R[st];i++) tmp[b[i]]=pre[en-1][b[i]]-pre[st][b[i]];
    for(int i=L[en];i<=r;i++) tmp[b[i]]=pre[en-1][b[i]]-pre[st][b[i]];
    for(int i=l;i<=R[st];i++)
    {
        int tt = ++tmp[b[i]];
        if(tt>ans) ans=tt,res=b[i];
        else if(tt==ans&&b[i]<res) res=b[i];
    }
    for(int i=L[en];i<=r;i++)
    {
        int tt = ++tmp[b[i]];
        if(tt>ans) ans=tt,res=b[i];
        else if(tt==ans&&b[i]<res) res=b[i];
    }
    return res;
}
map<pii,int> mp;
int main()
{
    //freopen("I-2.in","r",stdin);
    //freopen("ex_3.out","w",stdout);
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    GetHash(a,n);
    init();
    for(int i=1;i<=n;i++)
    {
        int l,r;
        read(l),read(r);
        if(mp.find(pii(l,r))==mp.end()) mp[pii(l,r)]=c[ask(l,r)];
        printf("%d\n",mp[pii(l,r)]);
    }
    return 0;
}

未完待续~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值