1. 程式人生 > >LOJ #3049. 「十二省聯考 2019」字符串問題

LOJ #3049. 「十二省聯考 2019」字符串問題

ack push continue back name != stream vector mem

LOJ #3049. 「十二省聯考 2019」字符串問題

https://loj.ac/problem/3049

題意:給你\(na\)\(A\)類串,\(nb\)\(B\)類串,\(m\)組支配關系,求一個長度很長的串\(t_1t_2...t_k\)滿足

\(t_i\)\(A\)類串,\(t_i\)能支配一個\(B\)類串,使得該\(B\)類串為\(t_{i+1}\)的前綴。

分析:

  • 一個簡單的暴力就是枚舉\(A_i\)後面能接的\(A_j\)進行連邊,然後拓撲序求一下最長路。
  • 很難優化,我們發現這相當於在中間塞入一個\(B\)串,然後發現如果答案不是無窮的話,每種\(B\)類串最多只用一次,那麽我們可以對於每個支配關系連邊,再由\(B\)
    串向把它當做前綴的那些\(A\)串連邊,跑新圖的最長路。
  • 對反串建立\(sam\),可以發現\(B\)串向\(parent\)樹的一個子樹上連邊,倍增定位可以做到一個\(log\)
  • 考慮\(B\)串可能大於A串的情況,這樣的話就很可能兩個串在同一個節點上但長度不同,我們可以對於每個\(A,B\)額外開出一個節點\(p\), \(p\rightarrow A\),\(B\rightarrow p\), \(p\)連一個前綴出來,總結點數是\(6n\)級別的吧。

代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <bitset>
#include <vector>
#include <iostream>
using namespace std;
typedef long long ll;
#define N 1200050
#define M 5000050
#define db(x) cerr<<#x<<" = "<<x<<endl
char w[N];
int n,la,lb,al[N],ar[N],bl[N],br[N],m,xx[N],yy[N];
int head[N],to[M],nxt[M],cnt,Q[N],du[N],tot,rt;
int ch[N][26],fa[N],len[N],uuz,pos[N],lst=1,f[21][N],ln[N],Lst[N];
ll g[N];
bool cmp(const int &x,const int &y) {
    return ln[x]==ln[y]?x<y:ln[x]>ln[y];
}
vector<int>V[N];
inline void add(int u,int v) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; du[v]++;
}
void insert(int x,int id) {
    int p=lst,np=++uuz,q,nq;
    len[np]=len[p]+1; lst=np;
    for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
    if(!p) fa[np]=rt;
    else {
        q=ch[p][x];
        if(len[q]==len[p]+1) fa[np]=q;
        else {
            nq=++uuz;
            fa[nq]=fa[q];
            len[nq]=len[p]+1;
            memcpy(ch[nq],ch[q],sizeof(ch[q]));
            fa[q]=fa[np]=nq;
            for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
        }
    }
}
void dfs(int x) {
    int i;
    for(i=1;(1<<i)<=uuz;i++) f[i][x]=f[i-1][f[i-1][x]];
    for(i=head[x];i;i=nxt[i]) {
        f[0][to[i]]=x;
        dfs(to[i]);
    }
}
int find(int l,int r) {
    int p=pos[r];
    int i;
    for(i=20;i>=0;i--) if(f[i][p]&&len[f[i][p]]>=r-l+1) p=f[i][p];
    return p;
}
void solve() {
    scanf("%s",w+1);
    n=strlen(w+1);
    reverse(w+1,w+n+1);
    int i,j;
    ll ans=0;
    scanf("%d",&la);
    for(i=1;i<=la;i++) scanf("%d%d",&al[i],&ar[i]);
    scanf("%d",&lb);
    for(i=1;i<=lb;i++) scanf("%d%d",&bl[i],&br[i]);
    scanf("%d",&m);
    tot=la+lb;
    for(i=1;i<=la;i++) {
        al[i]=n-al[i]+1,ar[i]=n-ar[i]+1,swap(al[i],ar[i]);
    }
    for(i=1;i<=lb;i++) {
        bl[i]=n-bl[i]+1,br[i]=n-br[i]+1,swap(bl[i],br[i]);
    }
    for(i=1;i<=la;i++) ln[i]=ar[i]-al[i]+1;
    for(i=1;i<=lb;i++) ln[i+la]=br[i]-bl[i]+1;
    rt=tot+1;lst=tot+1;uuz=tot+1;
    for(i=1;i<=n;i++) insert(w[i]-'a',i),pos[i]=lst;
    for(i=rt+1;i<=uuz;i++) add(fa[i],i);
    dfs(rt);
    for(i=rt;i<=uuz;i++) head[i]=0,du[i]=0;
    cnt=0;
    for(i=1;i<=m;i++) {
        scanf("%d%d",&xx[i],&yy[i]);
        add(xx[i],yy[i]+la);
    }
    for(i=1;i<=la;i++) {
        int p=find(al[i],ar[i]);
        V[p].push_back(i);
    }
    for(i=1;i<=lb;i++) {
        int p=find(bl[i],br[i]);
        V[p].push_back(i+la);
    }
    int ee=uuz;
    for(i=rt+1;i<=uuz;i++) {
        sort(V[i].begin(),V[i].end(),cmp);
        int lim=V[i].size(),lst=i;
        Lst[i]=i;
        if(lim==0) continue;
        for(j=0;j<lim;j++) {
            ee++;
            add(ee,lst);
            lst=ee;
            if(V[i][j]<=la) add(ee,V[i][j]);
            else add(V[i][j],ee);
        }
        Lst[i]=lst;
    }
    for(i=rt+1;i<=uuz;i++) add(fa[i],Lst[i]);
    uuz=ee;
    int l=0,r=0;
    for(i=1;i<=uuz;i++) if(!du[i]) Q[r++]=i;
    while(l<r) {
        int x=Q[l++];
        g[x]+=(x<=la?(ar[x]-al[x]+1):0);
        ans=max(ans,g[x]);
        for(i=head[x];i;i=nxt[i]) {
            du[to[i]]--; g[to[i]]=max(g[to[i]],g[x]);
            if(!du[to[i]]) Q[r++]=to[i];
        }
    }
    if(r!=uuz)
        puts("-1");
    else
        printf("%lld\n",ans);
    cnt=0;
    for(i=1;i<=n;i++) pos[i]=0;
    for(i=1;i<=uuz;i++) {
        fa[i]=len[i]=head[i]=du[i]=g[i]=Q[i]=0; V[i].clear();
    }
    for(i=0;(1<<i)<=uuz;i++) for(j=rt;j<=uuz;j++) f[i][j]=0;
    for(i=rt;i<=uuz;i++) memset(ch[i],0,sizeof(ch[i]));
    return ;
}
int main() {
    int T;
    scanf("%d",&T);
    while(T--) solve();
}

LOJ #3049. 「十二省聯考 2019」字符串問題