Codeforces 1073G Yet Another LCP Problem

題意

給出一個字符串,提問兩組位置,求兩組之間兩兩的後綴的LCP的和

題解

LCP要用到rank
設兩組爲 a[ ],b[ ]a[~],b[~ ]
將兩組的rank放到一起,排序
對每個 b[i]b[i] 只考慮他前面的 a[j]a[j](反過來再搞一遍就行)
在這裏插入圖片描述
已知 b[i1]b[i-1] 和它前面的LCP
首先,b[i1]b[i-1]b[i]b[i] 之間的可以暴力求
顯然,b[i1]b[i-1] 之前的可能會更改
假設,b[i1]b[i-1]b[i]b[i] 之間的LCP爲 tt
tt 大於等於 a[k1]a[k-1],顯然前面的那些都不用改,否則的話,就需要改,改多少,可以二分求得
即求 a[p]>=ta[p]>=t 的最小的 pp ,那麼 a[p..k2]a[p..k-2] 都修改爲 t
區間覆蓋,區間查詢,線段樹維護即可
複雜度: O(nlog2n)O(nlog^2n)

注意線段樹的 lazylazy 不能爲 0!!!!
因爲有區間覆蓋爲0的情況,坑了好久

UP
單調棧寫法:由於每個修改的是從後向前的若干個,而且是修改成同一個數
我們將相同LCP的合併存,維護LCP的單調遞增即可,同時維護前綴和(不維護也可以,用一個變量動態統計也行)

代碼

#include<bits/stdc++.h>
#define N 200010
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi 3.141592653589793
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<"      :   "<<x<<endl
#define mem(x,y) memset(x,0,sizeof(int)*(y+3))
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef pair<int,int> pp;
 
int LG[N];LL ans=0;
struct node{
    int x,y;
    bool operator < (const node zz) const{
        return x<zz.x;
    }
}e[N<<1];
 
struct SegTree{
    LL d[N<<2],a[N<<2];
    void push_down(int x,int l,int r,int t){
        if (d[x]==-1) return;
        d[x<<1]=d[x];   a[x<<1]=d[x]*(t-l+1);
        d[x<<1|1]=d[x]; a[x<<1|1]=d[x]*(r-t);
        d[x]=-1;
    }
    LL query(int x,int l,int r,int fl,int fr){
        if (l==fl && r==fr) return a[x];
        int t=(l+r)>>1;
        push_down(x,l,r,t);
        if (fr<=t)return query(x<<1,l,t,fl,fr);else
        if (fl>t) return query(x<<1|1,t+1,r,fl,fr);else
        return query(x<<1,l,t,fl,t)+query(x<<1|1,t+1,r,t+1,fr);
    } 
    void updata(int x,int l,int r,int fl,int fr,int y){
        if (l==fl && r==fr){
            d[x]=y;
            a[x]=(LL) y*(r-l+1);
            return;
        }
        int t=(l+r)>>1;
        push_down(x,l,r,t);
        if (fr<=t)  updata(x<<1,l,t,fl,fr,y);else
        if (fl>t)   updata(x<<1|1,t+1,r,fl,fr,y);else{
            updata(x<<1,l,t,fl,t,y);
            updata(x<<1|1,t+1,r,t+1,fr,y);
        }
        a[x]=a[x<<1]+a[x<<1|1];  
    } 
    void build(int x,int l,int r){
        a[x]=0; d[x]=-1;
        if (l==r) return;
        int t=(l+r)>>1;
        build (x<<1,l,t);
        build (x<<1|1,t+1,r);
       
    }
}ST;
struct SA{
    char s[N];
    int sa[N],t[N],t2[N],c[N],rak[N],height[N],f[N][20],num[N<<1],n,m;
    void build_sa(){
        int i,*x=t,*y=t2;
        for (i=0;i<m;i++)c[i]=0;
        for (i=0;i<n;i++)c[x[i]=s[i]]++;
        for (i=1;i<m;i++)c[i]+=c[i-1];
        for (i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
        for (int k=1;k<=n;k<<=1)     {
            int p=0;
            for (i=n-k;i<n;i++)y[p++]=i;
            for (i=0;i<n;i++)if (sa[i]>=k)y[p++]=sa[i]-k;
            for (i=0;i<m;i++)c[i]=0;
            for (i=0;i<n;i++)c[x[y[i]]]++;
            for (i=1;i<m;i++)c[i]+=c[i-1];
            for (i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);
            p=1; x[sa[0]]=0;
            for (i=1;i<n;i++)
                x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
            if (p>=n) break;
            m=p;
        }
    }
    void getheight(){
        int i,j,k=0;
        for (i=0;i<n;i++)rak[sa[i]]=i;
        for (i=0;i<n;i++){
            if (k)k--;
            if (!rak[i])continue;
            j=sa[rak[i]-1];
            while (s[i+k]==s[j+k])k++;
            height[rak[i]]=k;
        }
        for (int i=0;i<n;i++) f[i][0]=height[i];
            for (int k=1;(1<<k)<n;k++)
                for (int i=0;i<n;i++) if (i+(1<<k-1)<n)
                    f[i][k]=min(f[i][k-1],f[i+(1<<k-1)][k-1]);
    }
    int LCP(int l,int r) {
        if (l>r) swap(l,r);
        if (l==r) return n-sa[r]-1;
        l++;
        int k=LG[r-l];
        return min(f[l][k],f[r-(1<<k)+1][k]);
    }
    void work(int len){
        int cnt=0;
        for(int i=1,t=0;i<=len;i++) if (!e[i].y) num[i]=++cnt,t=i;else num[i]=t;
        ST.build(1,1,cnt);
        for(int i=1;i<=len;i++) if (e[i].y){
            int j=i-1;
            for(;j>0&&!e[j].y;j--)
                ST.updata(1,1,cnt,num[j],num[j],LCP(e[j].x,e[i].x));

            if (num[j]){
                int tmp=LCP(e[num[j]].x,e[i].x);
                int l=1,r=num[num[j]];
                int tm=ST.query(1,1,cnt,r,r);
                if (tm>tmp){
                    int tag;
                    while(l<=r){
                        int t=l+r>>1;
                        int tm=ST.query(1,1,cnt,t,t);
                        if (tm>=tmp) tag=t,r=t-1;else l=t+1;
                    }
                    ST.updata(1,1,cnt,tag,num[num[j]],tmp);   
                }
            }
            ans+=ST.query(1,1,cnt,1,cnt);
        }
    }
    void sol(){
        int k,l;
        scc(k,l);
        for(int i=1,x;i<=k;i++) {sc(x); e[i]={rak[x-1],0}; }
        for(int i=1,x;i<=l;i++){sc(x); e[i+k]={rak[x-1],1}; }
        ans=0;
        sort(e+1,e+k+l+1);
        work(k+l);
        reverse(e+1,e+k+l+1);
        work(l+k);
        printf("%lld\n",ans);
    }
}S;
 
 
int main(int argc, char const *argv[])
{
    for(int i=1;(1<<i)<N;i++) LG[1<<i]=1;
    for(int i=1;i<N;i++) LG[i]+=LG[i-1];
    int n,q;
    scc(n,q);
    scanf("%s",S.s);
    S.s[n]='$'; n++; S.n=n; S.m=300;
    S.build_sa();
    S.getheight();
    while(q--) S.sol();  
    return 0;
}

單調棧

#include<bits/stdc++.h>
#define N 200010
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi 3.141592653589793
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<"      :   "<<x<<endl
#define mem(x,y) memset(x,0,sizeof(int)*(y+3))
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef pair<int,int> pp;
 
int LG[N];LL ans=0;
struct node{
    int x,y;
    bool operator < (const node zz) const{
        return x<zz.x;
    }
}e[N<<1];
struct cc{
    int x,y;LL z;
}st[N],ls[N];
struct SA{
    char s[N];
    int sa[N],t[N],t2[N],c[N],rak[N],height[N],f[N][20],num[N<<1],n,m;
    void build_sa(){
        int i,*x=t,*y=t2;
        for (i=0;i<m;i++)c[i]=0;
        for (i=0;i<n;i++)c[x[i]=s[i]]++;
        for (i=1;i<m;i++)c[i]+=c[i-1];
        for (i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
        for (int k=1;k<=n;k<<=1)     {
            int p=0;
            for (i=n-k;i<n;i++)y[p++]=i;
            for (i=0;i<n;i++)if (sa[i]>=k)y[p++]=sa[i]-k;
            for (i=0;i<m;i++)c[i]=0;
            for (i=0;i<n;i++)c[x[y[i]]]++;
            for (i=1;i<m;i++)c[i]+=c[i-1];
            for (i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);
            p=1; x[sa[0]]=0;
            for (i=1;i<n;i++)
                x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
            if (p>=n) break;
            m=p;
        }
    }
    void getheight(){
        int i,j,k=0;
        for (i=0;i<n;i++)rak[sa[i]]=i;
        for (i=0;i<n;i++){
            if (k)k--;
            if (!rak[i])continue;
            j=sa[rak[i]-1];
            while (s[i+k]==s[j+k])k++;
            height[rak[i]]=k;
        }
        for (int i=0;i<n;i++) f[i][0]=height[i];
            for (int k=1;(1<<k)<n;k++)
                for (int i=0;i<n;i++) if (i+(1<<k-1)<n)
                    f[i][k]=min(f[i][k-1],f[i+(1<<k-1)][k-1]);
    }
    int LCP(int l,int r) {
        if (l>r) swap(l,r);
        if (l==r) return n-sa[r]-1;
        l++;
        int k=LG[r-l];
        return min(f[l][k],f[r-(1<<k)+1][k]);
    }
    void work(int len){
        int cnt=0;
        for(int i=1,t=0;i<=len;i++) if (!e[i].y) num[i]=++cnt,t=i;else num[i]=t;
        st[0]={-1,0,0}; int k=0;
        for(int i=1;i<=len;i++) if (e[i].y){
            int j=i-1,tot=0;
            for(;j>0&&!e[j].y;j--) ls[++tot]=cc{LCP(e[j].x,e[i].x),1,LCP(e[j].x,e[i].x)};
            if (num[j]){
                int t=LCP(e[j].x,e[i].x);
                while(st[k].x>t) ls[++tot]={t,st[k].y,1ll*t*st[k].y},k--;
            }
            for(int i=tot;i;i--){
                st[++k]=ls[i];
                if (st[k-1].x==st[k].x) {
                    k--;st[k].y+=st[k+1].y;st[k].z+=st[k+1].z;
                }else
                st[k].z+=st[k-1].z;
            }
            ans+=st[k].z;
        }
    }
    void sol(){
        int k,l;
        scc(k,l);
        for(int i=1,x;i<=k;i++) {sc(x); e[i]={rak[x-1],0}; }
        for(int i=1,x;i<=l;i++){sc(x); e[i+k]={rak[x-1],1}; }
        ans=0;
        sort(e+1,e+k+l+1);
        work(k+l);
        reverse(e+1,e+k+l+1);
        work(l+k);
        printf("%lld\n",ans);
    }
}S;
 
 
int main(int argc, char const *argv[])
{
    for(int i=1;(1<<i)<N;i++) LG[1<<i]=1;
    for(int i=1;i<N;i++) LG[i]+=LG[i-1];
    int n,q;
    scc(n,q);
    scanf("%s",S.s);
    S.s[n]='$'; n++; S.n=n; S.m=300;
    S.build_sa();
    S.getheight();
    while(q--) S.sol();  
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章