分块模板代码(自用)

题目

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL MAXN=1e5+5;
const LL MOD=1e9+7;
LL n,p,a[MAXN];
LL blksiz,blkcnt,pre[MAXN],nxt[MAXN],id[MAXN];
LL add[MAXN],val[325][325],sum[325][325];
LL blg[MAXN],ll[MAXN],rr[MAXN],f[MAXN];
struct node{
    LL x,id;
    bool operator <(const node &t)const{
        return x<t.x||(x==t.x&&id<t.id);
    }
}blk[325][325];
void addv(LL l,LL r,LL id,LL v){
    LL siz=rr[id]-ll[id]+1;
    for(LL i=1;i<=siz;i++){
        if(blk[id][i].id>=l&&blk[id][i].id<=r){
            blk[id][i].x+=v;
        }
    }
    sort(blk[id]+1,blk[id]+siz+1);
    for(LL i=1;i<=siz;i++){
        val[id][i]=f[blk[id][i].id-1];
        sum[id][i]=(sum[id][i-1]+val[id][i])%MOD;
    }
}
void ADD(LL l,LL r,LL v){
    if(blg[l]==blg[r]){
        addv(l,r,blg[l],v);
        return ;
    }
    LL bl=1,br=blkcnt;
    if(l==ll[blg[l]])bl=blg[l];
    else bl=blg[l]+1;
    if(r==rr[blg[r]])br=blg[r];
    else br=blg[r]-1;
    for(LL i=bl;i<=br;i++)add[i]+=v;
    if(l!=ll[blg[l]])addv(l,rr[blg[l]],blg[l],v);
    if(r!=rr[blg[r]])addv(ll[blg[r]],r,blg[r],v);
}
LL ask(LL l,LL r,LL id){
    LL res=0;
    LL siz=rr[id]-ll[id]+1;
    for(LL i=1;i<=siz;i++){
        if(blk[id][i].id>=l&&blk[id][i].id<=r){
            if(blk[id][i].x+add[id]<=p){//
                res=(res+val[id][i])%MOD;
            }
        }
    }
    return res;
}
LL query(LL l,LL r){
    LL res=0;
    if(blg[l]==blg[r])return ask(l,r,blg[l]);
    LL bl=1,br=blkcnt;
    if(l==ll[blg[l]])bl=blg[l];
    else bl=blg[l]+1;
    if(r==rr[blg[r]])br=blg[r];
    else br=blg[r]-1;
    for(LL i=bl;i<=br;i++){
        LL siz=rr[i]-ll[i]+1;
        LL l=1,r=siz,pos=0;
        while(l<=r){
            LL mid=(l+r)>>1;
            if(blk[i][mid].x+add[i]<=p){
                pos=mid;l=mid+1;
            }else{
                r=mid-1;
            }
        }
        res=(res+sum[i][pos])%MOD;
    }
    if(l!=ll[blg[l]])res=(res+ask(l,rr[blg[l]],blg[l]))%MOD;
    if(r!=rr[blg[r]])res=(res+ask(ll[blg[r]],r,blg[r]))%MOD;
    return res;
}
void update(LL x){
    LL now=blg[x+1];
    LL siz=rr[now]-ll[now]+1;
    for(LL i=1;i<=siz;i++){
        if(blk[now][i].id==x+1){
            val[now][i]=f[x];
            break;
        }
    }
    for(LL i=1;i<=siz;i++){
        sum[now][i]=(sum[now][i-1]+val[now][i])%MOD;
    }
}
int main(){
    freopen("home.in","r",stdin);
    freopen("home.out","w",stdout);
    scanf("%lld%lld",&n,&p);
    for(LL i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    blksiz=sqrt(n);
    for(LL i=1;i<=n;i++)id[i]=0;
    for(LL i=1;i<=n;i++)pre[i]=id[a[i]],id[a[i]]=i;
    for(LL i=1;i<=n;i++)id[i]=n+1;
    for(LL i=n;i>=1;i--)nxt[i]=id[a[i]],id[a[i]]=i;
    for(LL i=1;i<=n;i++)blg[i]=(i-1)/blksiz+1;
    blkcnt=blg[n];
    for(LL i=1;i<=blkcnt;i++)ll[i]=(i-1)*blksiz+1,rr[i]=min(n,i*blksiz);
    for(LL i=1;i<=blkcnt;i++){
        for(LL j=1;j<=rr[i]-ll[i]+1;j++){
            blk[i][j]={0ll,ll[i]+j-1};
        }
    }
    f[0]=1;
    update(0);
    for(LL i=1;i<=n;i++){
        ADD(pre[i]+1,i,1);
        if(pre[i]>=1&&pre[i]<=n)ADD(pre[pre[i]]+1,pre[i],-1);
        f[i]=query(1,i);
        update(i);
    }
    printf("%lld",f[n]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值