• LG P5211 [ZJOI2017]字符串


    Description

    维护一个动态字符串 $s[1 cdots n]$,字符串的字符集是所有 $|x| leq 10^9$ 的整数。要求支持两个操作:

    1) 输入 $l, r, d$,对于所有 $l leq i leq r$,将 $s[i]$ 修改为 $s[i] + d$,注意 $d$ 可能是负数。

    2) 输入 $l, r$,输出子串 $s[l..r]$ 的字典序最小的后缀的起点位置。即,如果最小后缀是 $s[p..r],(l leq p leq r)$,请输出 $p$。

    Solution

    线段树每个节点维护以区间右端点为右端点,可能成为最小后缀(所有后缀减去一定不是最小后缀)的所有左端点

    强制要去线段树的左区间大于等于右区间,按照以下的方式更新:

    继承右区间的所有端点,从左区间中继承一个端点

    将左区间保存的所有后缀后接上右区间子串,比较它们的大小,如果两个串因字母不同而比出大小,取字典序较小的;如果因长度不同而比出大小,取长度大的,因为:

    设这个较长的串为$a$,较短的串为$b$,那么$b$是$a$的border,所以$a$是有周期的,所以某个左端点在右区间的后缀必是$a$的前缀,设其为$c$,如果$b$后接的字母比$a$中对应位置的大,$b$不是最小的;如果$b$后接的字母比$a$中对应位置的小,$c$就比$b$小,$b$不是最小的,所以此时取长度大的

    所以每个线段树节点维护的左端点个数不超过$log n$

    并分块维护原串的哈希值,修改时间复杂度$O(msqrt n)$

    询问时在线段树上找到区间,比较这些区间内所有后缀串的大小,时间复杂度$O(m log^3 n)$

    预处理建树时间复杂度$O(n log^2 n)$,预处理分块哈希时间复杂度$O(n)$

    代码抄的

    #pragma GCC optimize(2)
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int n,q,s[200005],TP;
    const int mod1=1e9+9,mod2=1e9+7,bas=998244353,B=300;
    struct str{
        int st,len;
    }ans;
    inline int read(){
        int f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
        return f*w;
    }
    long long ksm(long long a,long long p,long long m){
        long long ret=1;
        while(p){
            if(p&1)(ret*=a)%=m;
            (a*=a)%=m,p>>=1;
        }
        return ret;
    }
    namespace has{
        int bi[200005],bj[200005];
        long long mi1[200005],mi2[200005],imi1[200005],imi2[200005],sf1[200005],sf2[200005],pre1[200005],pre2[200005];
        struct blk{
            int ch[305],siz,ad;
            long long sp1[305],sp2[305],pr1[305],pr2[305];
            int& operator [](const int& x){return ch[x];}
            void calh(){for(int i=1;i<=siz;i++)pr1[i]=(pr1[i-1]+mi1[i-1]*ch[i]%mod1+mod1)%mod1,pr2[i]=(pr2[i-1]+mi2[i-1]*ch[i]%mod2+mod2)%mod2;}
            void init(){
                for(int i=1;i<=siz;i++)sp1[i]=(sp1[i-1]+mi1[i-1])%mod1,sp2[i]=(sp2[i-1]+mi2[i-1])%mod2;
                calh();
            }
            long long gh1(int x){return (pr1[x]+sp1[x]*(ad+mod1))%mod1;}
            long long gh2(int x){return (pr2[x]+sp2[x]*(ad+mod2))%mod2;}
            void upd(int l,int r,int v){
                for(int i=1;i<=siz;i++)ch[i]+=ad;
                for(int i=l;i<=r;i++)ch[i]+=v;
                ad=0,calh();
            }
        }bl[705];
        void calc(int st){for(int i=st;i<=bi[n];i++)pre1[i]=(pre1[i-1]+bl[i].gh1(bl[i].siz)*sf1[i-1])%mod1,pre2[i]=(pre2[i-1]+bl[i].gh2(bl[i].siz)*sf2[i-1])%mod2;}
        void init(){
            for(int i=1;i<=n;i++)bi[i]=(i-1)/B+1,bj[i]=(i-1)%B+1;
            mi1[0]=mi2[0]=1,imi1[0]=imi2[0]=1,bl[bi[n]].siz=bj[n],sf1[0]=sf2[0]=1;
            for(int i=1;i<=n;i++)mi1[i]=mi1[i-1]*bas%mod1,mi2[i]=mi2[i-1]*bas%mod2;
            long long inv=ksm(bas,mod1-2,mod1);
            for(int i=1;i<=n;i++)imi1[i]=imi1[i-1]*inv%mod1;
            inv=ksm(bas,mod2-2,mod2);
            for(int i=1;i<=n;i++)imi2[i]=imi2[i-1]*inv%mod2;
            for(int i=1;i<=n;i++)bl[bi[i]][bj[i]]=s[i];
            for(int i=1;i<bi[n];i++)bl[i].siz=B;
            for(int i=1;i<=bi[n];i++)bl[i].init();
            for(int i=1;i<=bi[n];i++)sf1[i]=sf1[i-1]*mi1[bl[i].siz]%mod1,sf2[i]=sf2[i-1]*mi2[bl[i].siz]%mod2;
            calc(1);
        }
        long long gh1(int x){
            int t=bi[x]-1;
            return (pre1[t]+bl[t+1].gh1(bj[x])*sf1[t])%mod1;
        }
        long long gh2(int x){
            int t=bi[x]-1; 
            return (pre2[t]+bl[t+1].gh2(bj[x])*sf2[t])%mod2;
        }
        int gt(int x){return bl[bi[x]][bj[x]]+bl[bi[x]].ad;}
        bool check(int p1,int p2,int len){
            long long v1=(gh1(p1+len-1)+mod1-gh1(p1-1))*imi1[p1-1]%mod1,v2=(gh1(p2+len-1)+mod1-gh1(p2-1))*imi1[p2-1]%mod1;
            if(v1!=v2)return false;
            v1=(gh2(p1+len-1)+mod2-gh2(p1-1))*imi2[p1-1]%mod2,v2=(gh2(p2+len-1)+mod2-gh2(p2-1))*imi2[p2-1]%mod2;
            return v1==v2;
        }
        void update(int l,int r,int v){
            int p1=bi[l],p2=bi[r];
            if(p1==p2)bl[p1].upd(bj[l],bj[r],v);
            else{
                bl[p1].upd(bj[l],bl[p1].siz,v),bl[p2].upd(1,bj[r],v);
                for(int i=p1+1;i<p2;i++)bl[i].ad+=v;
            }
            calc(p1);
        }
    }
    bool operator <(str a,str b){
        int c1=has::gt(a.st),c2=has::gt(b.st),l=0,r=min(a.len,b.len),t=0;
        if(c1!=c2)return c1<c2;
        if(has::check(a.st,b.st,r))return (a.len>b.len)^TP;
        while(l<=r){
            int mid=l+r>>1;
            if(has::check(a.st,b.st,mid))l=mid+1,t=mid;
            else r=mid-1;
        }
        return has::gt(a.st+t)<has::gt(b.st+t);
    }
    str operator +(str a,int b){return (str){a.st,a.len+b};}
    namespace tr{
        int cnt[800005];
        str v[800005][20];
        void pushup(int i,int len){
            cnt[i]=cnt[i<<1|1];
            for(int j=1;j<=cnt[i<<1|1];j++)v[i][j]=v[i<<1|1][j];
            str minn=v[i<<1][1]+len;
            for(int j=2;j<=cnt[i<<1];j++)minn=min(minn,v[i<<1][j]+len);
            v[i][++cnt[i]]=minn;
        }
        void build(int i,int l,int r){
            if(r-l==1){v[i][++cnt[i]]=(str){r,1};return;}
            int mid=l+r>>1;
            build(i<<1,l,mid),build(i<<1|1,mid,r),pushup(i,r-mid);
        }
        void update(int i,int l,int r,int L,int R){
            if(L<=l&&r<=R)return;
            int mid=l+r>>1;
            if(L<mid)update(i<<1,l,mid,L,R);
            if(R>mid)update(i<<1|1,mid,r,L,R);
            pushup(i,r-mid);
        }
        void query(int i,int l,int r,int L,int R,int p){
            if(L<=l&&r<=R){
                int j=1;
                if(ans.st==-1)ans=str{v[i][1].st,p-v[i][1].st+1},j=2;
                for(;j<=cnt[i];j++)ans=min(ans,(str){v[i][j].st,p-v[i][j].st+1});
                return;
            }
            int mid=l+r>>1;
            if(L<mid)query(i<<1,l,mid,L,R,p);
            if(R>mid)query(i<<1|1,mid,r,L,R,p);
        }
    }
    int main(){
        n=read(),q=read();
        for(int i=1;i<=n;i++)s[i]=read();
        has::init(),tr::build(1,0,n);
        for(;q;q--){
            int opt=read(),l=read(),r=read();
            if(opt==1){
                int d=read();
                TP=0,has::update(l,r,d),tr::update(1,0,n,l-1,r);
            }
            else TP=1,ans=(str){-1,0},tr::query(1,0,n,l-1,r,r),printf("%d
    ",ans.st);
        }
        return 0;
    }
    [ZJOI2017]字符串
  • 相关阅读:
    BZOJ 1021 循环的债务
    BZOJ 1019 汉诺塔
    BZOJ 1018 堵塞的交通
    BZOJ 1017 魔兽地图
    BZOJ 1016 最小生成树计数
    Luogu 3008 [USACO11JAN]道路和飞机Roads and Planes
    Luogu 3625 [APIO2009]采油区域
    Luogu 4139 上帝与集合的正确用法
    Luogu 3629 [APIO2010]巡逻
    Luogu 3626 [APIO2009]会议中心
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14571564.html
Copyright © 2020-2023  润新知