UOJ584 【ZJOI2020】字符串

UOJ584 【ZJOI2020】字符串

\(\operatorname{Runs}\)

本题是询问区间本质不同元素的问题,可以考虑对询问离线,然后依次加入元素并打上标记,同时撤销上一次修改的位置。

要保证复杂度,就必须保证所有本质不同平方串只能被插入一次。

我们考虑到,如果我们依次将每一个\(\operatorname{Run}\)中的本质不同平方串加入,这样总插入次数就是\(O(n \log n)\)了,但是这样我们就无法处理穿过当前位置的\(\operatorname{Run}\),我们不得不不断插入、撤销同样的平方串,这样就导致时间复杂度出现了严重问题。

我们选择把穿过当前位置的平方串作为第二类贡献单独处理,由于以一个位置结尾的本原平方串数量为\(O(\log n)\),那么我们直接暴力枚举,然后直接计算枚举的\(\operatorname{Run}\)的开头到当前位置的答案。每次到达一个\(\operatorname{Run}\)的末尾时,将整个\(\operatorname{Run}\)的平方串插入。

显然这样两者会出现重复,我们选择把重复部分归为第二类贡献,每扫到一个位置,我们枚举能够产生平方串的、经过它的\(\operatorname{Run}\),然后对以该位置结尾极长的平方串,撤销其在之前出现的位置,容易发现这样做能够恰好撤销所有第一类贡献在第二类贡献中的重复。

利用树状数组维护,同时维护一个哈希表即可。

时间复杂度:\(O(n \log^2 n+q \log n)\)

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define N 200005
#define M 10000005
#define pr pair<int,int>
#define mp make_pair
#define ll long long
#define iIT vector<int> :: iterator
#define pIT vector< pr > :: iterator
using namespace std;
const int p1=999999797;
const int p2=999999883;
const int p3=6662333;
const int bs=277;
const int bs2=233;
vector< pr >e[N];
vector<int>g[N],ir[N];
struct Hash_map
{
    int tot,fr[p3+5],nxt[M];
    pr d[M];
    int val[M];
    int add(pr x)
    {
        int key(((ll)x.first*bs2+x.second)%p3);
        ++tot,d[tot]=x,val[tot]=-1,nxt[tot]=fr[key],fr[key]=tot;
        return tot;
    }
    int ser(pr x)
    {
        int key(((ll)x.first*bs2+x.second)%p3);
        for (int i=fr[key];i;i=nxt[i])
            if (d[i]==x)
                return i;
        return -1;
    }
}f;
int n,m,q,l,r,m1[N],m2[N],h1[N],h2[N];
int t,st[N],Ly[N];
int ans[N];
char s[N];
struct Run
{
    int l,r,p;
    Run () {}
    Run (int A,int B,int C):l(A),r(B),p(C) {}
    bool operator < (const Run &A) const
    {
        if (l!=A.l)
            return l<A.l;
        return r<A.r;
    }
    bool operator == (const Run &A) const
    {
        return l==A.l && r==A.r;
    }
}runs[N << 1];
bool ckl(int l,int r,int T)
{
    return ((ll)h1[l]-(ll)h1[l-T]*m1[T]-h1[r]+(ll)h1[r-T]*m1[T])%p1==0 && ((ll)h2[l]-(ll)h2[l-T]*m2[T]-h2[r]+(ll)h2[r-T]*m2[T])%p2==0;
}
bool ckr(int l,int r,int T)
{
    return ((ll)h1[l+T-1]-(ll)h1[l-1]*m1[T]-h1[r+T-1]+(ll)h1[r-1]*m1[T])%p1==0 && ((ll)h2[l+T-1]-(ll)h2[l-1]*m2[T]-h2[r+T-1]+(ll)h2[r-1]*m2[T])%p2==0;
}
int extl(int l,int r)
{
    int L(0),R(l),g(0);
    while (L<=R)
    {
        int mid(L+R >> 1);
        if (ckl(l,r,mid))
            g=mid,L=mid+1; else
            R=mid-1;
    }
    return g;
}
int extr(int l,int r)
{
    int L(0),R(n-r+1),g(0);
    while (L<=R)
    {
        int mid(L+R >> 1);
        if (ckr(l,r,mid))
            g=mid,L=mid+1; else
            R=mid-1;
    }
    return g;
}
bool cmp(int l,int r)
{
    int len(extr(l,r));
    return s[l+len]<s[r+len];
}
void Lyndon(bool op)
{
    t=0,Ly[n]=n,st[0]=n+1,st[++t]=n;
    for (int i=n-1;i;--i)
    {
        while (t && cmp(i,st[t])==op)
            --t;
        Ly[i]=st[t]-1,st[++t]=i;
    }
}
void check(int l,int r)
{
    int cl(extl(l,r)),cr(extr(l,r));
    if (cl+cr-1>=r-l)
        runs[++m]=Run(l-cl+1,r+cr-1,r-l);
}
pr calc(int l,int r)
{
    int e1(((ll)h1[r]-(ll)h1[l-1]*m1[r-l+1])%p1);
    e1=(e1<0)?e1+p1:e1;
    int e2(((ll)h2[r]-(ll)h2[l-1]*m2[r-l+1])%p2);
    e2=(e2<0)?e2+p2:e2;
    return mp(e1,e2);
}
int c[N];
#define lowbit(x) (x & (-x))
void update(int x,int z)
{
    while (x<=n)
        c[x]+=z,x+=lowbit(x);
}
int calc(int x)
{
    int ans(0);
    while (x)
        ans+=c[x],x-=lowbit(x);
    return ans;
}
int main()
{
    scanf("%d%d",&n,&q);
    scanf("%s",s+1);
    m1[0]=m2[0]=1;
    for (int i=1;i<=n;++i)
    {
        m1[i]=(ll)m1[i-1]*bs%p1,h1[i]=((ll)h1[i-1]*bs+s[i])%p1;
        m2[i]=(ll)m2[i-1]*bs%p2,h2[i]=((ll)h2[i-1]*bs+s[i])%p2;
    }
    for (int op=0;op<=1;++op)
    {
        Lyndon(op);
        for (int i=1;i<=n;++i)
            check(i,Ly[i]+1);
    }
    sort(runs+1,runs+m+1),m=unique(runs+1,runs+m+1)-runs-1;
    for (int i=1;i<=m;++i)
    {
        int l(runs[i].l),r(runs[i].r),p(runs[i].p);
        for (int j=l+(p << 1)-1;j<=r;++j)
            g[j].push_back(i);
        ir[r].push_back(i);
    }
    for (int i=1;i<=q;++i)
    {
        scanf("%d%d",&l,&r);
        e[r].push_back(mp(l,i));
    }
    for (int i=1;i<=n;++i)
    {
        for (iIT it=g[i].begin();it!=g[i].end();++it)
        {
            int id(*it),lst(i-(i-runs[id].l+1)/(runs[id].p << 1)*(runs[id].p << 1)+1);
            pr ha(calc(lst,i));
            int mt=f.ser(ha);
            if (~mt && ~f.val[mt])
                update(f.val[mt],-1),f.val[mt]=-1;
        }
        int ci(calc(i));
        for (pIT pt=e[i].begin();pt!=e[i].end();++pt)
        {
            int lef(pt->first);
            ans[pt->second]=ci-calc(lef-1);
            for (iIT it=g[i].begin();it!=g[i].end();++it)
            {
                int id(*it),len(i-max(runs[id].l,lef)+1),p(runs[id].p);
                int cyc(len/(p << 1)),t(len%(p << 1));
                if (!cyc)
                    continue;
                if (t>=p-1)
                    ans[pt->second]+=cyc*p; else
                    ans[pt->second]+=cyc*(t+1)+(cyc-1)*(p-t-1);
            }
        }
        for (iIT it=ir[i].begin();it!=ir[i].end();++it)
        {
            int id(*it),l(runs[id].l),r(runs[id].r),p(runs[id].p);
            for (int j=l;j<=r-(p << 1)+1;++j)
            {
                int lst(j+(r-j+1)/(p << 1)*(p << 1)-1);
                pr ha(calc(j,lst));
                int mt=f.ser(ha);
                if (~mt && ~f.val[mt])
                    update(f.val[mt],-1);
                if (!~mt)
                    mt=f.add(ha);
                f.val[mt]=j;
                update(j,1);
            }
        }
    }
    for (int i=1;i<=q;++i)
        printf("%d\n",ans[i]);
    return 0;
}
posted @ 2021-04-13 16:03  GK0328  阅读(102)  评论(0编辑  收藏  举报