dtoi4720 区间

 题意:

     求已知序列的所有本质不同的子区间的最大值之和。

题解:

     对于每一个位置i,我们需要计算出最短的区间[i,j],使得[i,j]的字符串没有被算过,那么[i,j+1],[i,j+2],[i,j+3]...[i,n]都不会被算过。

     统计答案很容易,方法应该也不少。我的做法是定义每一个点的父亲为后面第一个比它大的位置,然后倍增一下再计算一下就可以算出答案。

     接下来就是如何求出上述区间,其实就是需要求出一个最小的值a,满足所有后缀j(j<i)与后缀i的最长公共前缀小于a。

     然后我考场上以为两个log是可以过的,就直接写了个二分,然后SA上再来了个二分,于是愉快的TLE了。

     后来想卡常,但是怎么都卡不过去只好又写了一大堆代码改成了一个log的做法,具体如下

     其实我们只需要知道前i-1个后缀中在SA上位置最接近第i个后缀在SA上的位置的那左右两个即可,然后用rmq求一下height的最小值即可。

     线段树维护它写着写着,代码就5.6k了

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int INF=1313331331;
int T,n,a[200002],lgg[200002],fa[22][200002],q[200002],len,tax[200002],sa[200002],rk[200002],cnt;
int h[22][200002],Min[22][200002],las[200002],tp[200002],head[200002],x,y;
unsigned long long has[200002],cf[200002];
long long w[200002];
typedef struct{
    int to,nex;
}P;
P p[200002];
typedef struct{
    int Max,Min,f1,f2;
}XDS;
XDS xds[800002];
void add(int x,int y){
    p[++cnt].to=y;p[cnt].nex=head[x];head[x]=cnt;
}
bool cmp(int x,int y){
    return (a[x]<a[y]);
}
inline bool pd(int x,int y,int l,int r){
    if (x<l)return (has[y]-has[x-1])*cf[l-x]==(has[r]-has[l-1]);
    else return (has[y]-has[x-1])==(has[r]-has[l-1])*cf[x-l];
}
inline int minh(int x,int y){
    int len=y-x+1;
    return min(h[lgg[len]][x],h[lgg[len]][y-(1<<lgg[len])+1]);
}
inline int bj(int x,int y){
    int lef=0,righ=min(n-x+1,n-y+1),mid;
    while(lef<righ)
    {
        mid=(lef+righ+1)/2;
        if (pd(x,x+mid-1,y,y+mid-1))lef=mid;else righ=mid-1;
    }
    return lef;
}
int read(){
    int f=0;char ch=getchar();
    while(ch<'0' || ch>'9')ch=getchar();
    while(ch>='0' && ch<='9'){f=f*10+ch-48;ch=getchar();}
    return f;
}
void pushdown(int root){
    if (xds[root].f1)
    {
        if (xds[root].f1>xds[root*2].Max)xds[root*2].Max=xds[root].f1;
        if (xds[root].f1>xds[root*2+1].Max)xds[root*2+1].Max=xds[root].f1;
        if (!xds[root*2].f1 || xds[root].f1>xds[root*2].f1)xds[root*2].f1=xds[root].f1;
        if (!xds[root*2+1].f1 || xds[root].f1>xds[root*2+1].f1)xds[root*2+1].f1=xds[root].f1;
        xds[root].f1=0;
    }
    if (xds[root].f2)
    {
        if (xds[root].f2<xds[root*2].Min)xds[root*2].Min=xds[root].f2;
        if (xds[root].f2<xds[root*2+1].Min)xds[root*2+1].Min=xds[root].f2;
        if (!xds[root*2].f2 || xds[root].f2<xds[root*2].f2)xds[root*2].f2=xds[root].f2;
        if (!xds[root*2+1].f2 || xds[root].f2<xds[root*2+1].f2)xds[root*2+1].f2=xds[root].f2;
        xds[root].f2=0;
    }
}
void build(int root,int begin,int end){
    xds[root].f1=xds[root].f2=0;
    if (begin==end)
    {
        xds[root].Max=-1e9;xds[root].Min=1e9;
        return;
    }
    int mid=(begin+end)/2;
    build(root*2,begin,mid);build(root*2+1,mid+1,end);
    xds[root].Max=max(xds[root*2].Max,xds[root*2+1].Max);
    xds[root].Min=min(xds[root*2].Min,xds[root*2+1].Min);
}
void chaxun(int root,int begin,int end,int wz){
    if (begin>wz || end<wz)return;
    if (begin==end)
    {
        x=xds[root].Max;y=xds[root].Min;return;
    }
    int mid=(begin+end)/2;pushdown(root);
    chaxun(root*2,begin,mid,wz);chaxun(root*2+1,mid+1,end,wz);
}
void gxmax(int root,int begin,int end,int begin2,int end2,int z){
    if (begin>end2 || end<begin2)return;
    if (begin>=begin2 && end<=end2)
    {
        if (z>xds[root].Max)xds[root].Max=z;
        if (!xds[root].f1 || z>xds[root].f1)xds[root].f1=z;
        return;
    }
    int mid=(begin+end)/2;pushdown(root);
    gxmax(root*2,begin,mid,begin2,end2,z);gxmax(root*2+1,mid+1,end,begin2,end2,z);
    xds[root].Max=max(xds[root*2].Max,xds[root*2+1].Max);
}
void gxmin(int root,int begin,int end,int begin2,int end2,int z){
    if (begin>end2 || end<begin2)return;
    if (begin>=begin2 && end<=end2)
    {
        if (z<xds[root].Min)xds[root].Min=z;
        if (!xds[root].f2 || z<xds[root].f2)xds[root].f2=z;
        return;
    }
    int mid=(begin+end)/2;pushdown(root);
    gxmin(root*2,begin,mid,begin2,end2,z);gxmin(root*2+1,mid+1,end,begin2,end2,z);
    xds[root].Min=min(xds[root*2].Min,xds[root*2+1].Min);
}
int main()
{
    for (int i=1;i<=200000;i++)
    for (int j=0;(1<<j)<=i;j++)lgg[i]=j;
    cf[0]=1;
    for (int i=1;i<=200000;i++)cf[i]=cf[i-1]*INF;
    T=read();
    while(T--)
    {
        n=read();len=0;
        for (int i=1;i<=n;i++)a[i]=read();
        for (int i=n;i>=1;i--)
        {
            while(len && a[i]>=a[q[len]])len--;
            if (len)fa[0][i]=q[len];else fa[0][i]=0;
            q[++len]=i;
            if (fa[0][i])w[i]=(long long)a[i]*(fa[0][i]-i)+w[fa[0][i]];
            else w[i]=(long long)a[i]*(n-i+1);
        }
        for (int i=1;i<=17;i++)
        for (int j=1;j<=n;j++)
        fa[i][j]=fa[i-1][fa[i-1][j]];
        for (int i=1;i<=n;i++)
        {
            has[i]=has[i-1]+cf[i-1]*a[i];
            sa[i]=i;
        }
        sort(sa+1,sa+n+1,cmp);
        rk[sa[1]]=1;
        for (int i=2;i<=n;i++)
        if (a[sa[i]]==a[sa[i-1]])rk[sa[i]]=rk[sa[i-1]];else rk[sa[i]]=rk[sa[i-1]]+1;
        for (int i=1;i<=17;i++)
        {
            for (int j=0;j<=n;j++){las[j]=rk[j];tax[j]=0;head[j]=-1;}
            cnt=0;
            for (int j=1;j<=n;j++)
            {
                if (j+(1<<i-1)>n)tp[j]=0;else tp[j]=j+(1<<i-1);
                tax[rk[j]]++;add(rk[tp[j]],j);
            }
            for (int j=1;j<=n;j++)tax[j]+=tax[j-1];
            for (int j=n;j>=0;j--)
            for (int k=head[j];k!=-1;k=p[k].nex)
            sa[tax[rk[p[k].to]]--]=p[k].to;
            rk[sa[1]]=1;
            for (int j=2;j<=n;j++)
            if (las[sa[j]]==las[sa[j-1]] && las[tp[sa[j]]]==las[tp[sa[j-1]]])rk[sa[j]]=rk[sa[j-1]];else rk[sa[j]]=rk[sa[j-1]]+1;
        }
        build(1,1,n);
        for (int i=1;i<=n;i++)Min[0][i]=sa[i];
        for (int i=1;i<n;i++)h[0][i]=bj(sa[i],sa[i+1]);
        for (int i=1;i<=17;i++)
        for (int j=1;j<=n;j++)
        {
            if (j+(1<<i-1)<=n)h[i][j]=min(h[i-1][j],h[i-1][j+(1<<i-1)]);
            if (j+(1<<i-1)<=n)Min[i][j]=min(Min[i-1][j],Min[i-1][j+(1<<i-1)]);
        }
        long long ans=0;
        for (int i=1;i<=n;i++)
        {
            int Max=0;
            chaxun(1,1,n,rk[i]);
            if (x>=1 && x<=n && x<rk[i])Max=max(Max,minh(x,rk[i]-1));
            if (y>=1 && y<=n && y>rk[i])Max=max(Max,minh(rk[i],y-1));
            y=i+Max;
            if (y<=n)
            {
                int x=i;
                for (int j=17;j>=0;j--)
                if (fa[j][x]!=0 && fa[j][x]<=y)x=fa[j][x];
                if (fa[0][x])ans+=(long long)a[x]*(fa[0][x]-y)+w[fa[0][x]];
                else ans+=(long long)a[x]*(n-y+1);
            }
            if (rk[i]>1)gxmin(1,1,n,1,rk[i]-1,rk[i]);
            if (rk[i]<n)gxmax(1,1,n,rk[i]+1,n,rk[i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2020-02-16 18:23  1124828077ccj  阅读(93)  评论(0编辑  收藏  举报