Gym - 102302 K - Candies —— 主席树+后缀数组

This way

题意:

给你一个长度为n的数组,让你取一段子区间使得这个区间里值得和>=L,<=R
问你有多少个本质不同的区间。

题解:

难点在于本质不同。
我一开始想的是后缀自动机,但是发现忘了怎么做了,而且好像比较难处理。
转换成后缀数组时,发现height数组是知道排名为i和排名为i-1的后缀的最长公共前缀的,那么我们只需要按照sa数组的顺序便利,查询的区间是height[i]+sa[i]到n。
由于我找的后缀数组的板子,计算是从0到n-1的,所以做起来会比较麻烦。

#include
using namespace std;
#define ll long long
const int N=1e6+10;
int wa[N],wb[N],wv[N],we[N],rk[N];
int cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
void build_sa(int *r,int *sa,int n,int m){
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0;i=0;i--)sa[--we[x[i]]]=i;
    for(j=1,p=1;p=j)y[p++]=sa[i]-j;
        for(i=0;i=0;i--)sa[--we[wv[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i>1;
    if(mid>=pos)
        update(l,mid,ls[root]=++tot,ls[last],pos);
    else
        update(mid+1,r,rs[root]=++tot,rs[last],pos);
}
ll query(int l,int r,int root,int last,int ql,int qr)
{
    if(l>=ql&&r<=qr)
        return num[root]-num[last];
    int mid=l+r>>1;
    ll ans=0;
    if(mid>=ql)
        ans=query(l,mid,ls[root],ls[last],ql,qr);
    if(mid=0?sum[i-1]:0)+a[i];
        b[++all]=sum[i];
        b[++all]=a[i];
    }
    sort(b+1,b+1+all);
    all=unique(b+1,b+1+all)-b-1;
    for(int i=0;i=2?sum[pos-2]:0;
        int l=lower_bound(b+1,b+1+all,s+L)-b;
        int r=upper_bound(b+1,b+1+all,s+R)-b-1;
        if(l<=r)
            ans+=query(1,all,rt[n],rt[pos+height[i]-1],l,r);
    }
    printf("%lld\n",ans);
    return 0;
}
/**/

你可能感兴趣的:(主席树,后缀数组)