1. 程式人生 > 實用技巧 >Deepin 安裝 xRDP,Window使用RDP遠端連線

Deepin 安裝 xRDP,Window使用RDP遠端連線

Luogu4770 [NOI2018]你的名字

\(SAM+LCT+\)倍增

好歹自己切了一道字串黑題,這幾天字串沒白頹。

觀察原問題,如果模式串不是區間形式的話,很容易想到一個做法,就是對於輸入串每一個\(r\)位置,除去\(r\)所在的字尾中不滿足條件的字尾,顯然不滿足條件的字尾一定是一段區間,所以從\(r\)字尾在\(SAM\)\(parent\)樹上的匹配的最深位置\(x\)\(root\)路徑中所有的字尾都需要砍掉。

然而模式串是一段區間,可以發現,不滿足條件的串仍然是\(x \rightarrow root\)路徑上一個位置\(y\)\(root\)的路徑,因為新的不滿足條件的字尾一定是原問題的子集。

那麼我們考慮找到那個節點,也就是說,該節點代表的集合中存在串\(s\),使得它在\(r\)之前最後出現的位置的左端點\(L \ge l\)

參考Luogu6292 區間本質不同子串個數的做法,將\(r\)指標一位一位掃過去,同時用\(LCT\)更新最右的右端點。

同時,在\(parent\)樹上,節點的\(l\)端點在\(x \rightarrow root\)上一定單調遞增,因為對於最右\(r\)端點,顯然祖先一定不小於子孫,對於長度,祖先又比子孫小。

既然具有了單調性,我們就可以考慮倍增了,向\(L<l\)的最淺節點跳。在細節上,注意我們最終跳到的節點可能會存在一部分子串滿足題意,這些必須統計。

還有一個問題需要處理,就是對於輸入的串,即使除去了不滿足題意的串,其自身的串依然會存在重複情況,對此,我們對輸入串仍需要建立\(SAM\)

那麼我們在\(parent\)樹上打標記,我們已經找出了一個字尾長度在\([1,t]\)範圍內是不合法的,這在新的\(SAM\)上仍然對應一個節點到根的路徑,再次倍增。

最後一次\(DFS\)統計答案即可。

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#define pr pair<int,int>
#define mp make_pair
#define ll long long
#define IT vector< pr > :: iterator
#define N 500005
#define qN 100005
using namespace std;
int l,r;
int lth[qN],g[N << 1];
ll ans[qN];
char s[N];
string T[qN];
vector< pr >e[N];
int n,q;
struct edge
{
    int nxt,v;
    edge (int Nxt=0,int V=0)
    {
        nxt=Nxt,v=V;
    }
}E[N << 1];
int tot,fr[N << 1];
void add(int x,int y)
{
    ++tot;
    E[tot]=edge(fr[x],y),fr[x]=tot;
}
struct SAM
{
    int lst=1,cnt=1,tr[N << 1][26],pre[N << 1],len[N << 1];
    int f[N << 1][22];
    void ins(int c)
    {
        int p=lst,q,np;
        lst=np=++cnt;
        len[np]=len[p]+1;
        for (;p && !tr[p][c];p=pre[p])
            tr[p][c]=np;
        if (!p) 
            pre[np]=1; else
            {
                q=tr[p][c];
                if (len[p]+1==len[q])
                    pre[np]=q; else
                    {
                        int g=++cnt;
                        memcpy(tr[g],tr[q],sizeof(tr[q]));
                        len[g]=len[p]+1,pre[g]=pre[q];
                        for (;p && tr[p][c]==q;p=pre[p])
                            tr[p][c]=g;
                        pre[np]=pre[q]=g;
                    }
            }
    }
    void Do_st()
    {
        for (int i=1;i<=cnt;++i)
            f[i][0]=pre[i];
        for (int j=1;j<=20;++j)
            for (int i=1;i<=cnt;++i)
                f[i][j]=f[f[i][j-1]][j-1];
    }
    void build()
    {
        for (int i=2;i<=cnt;++i)
            add(pre[i],i);
    }
    void Clear()
    {
        memset(tr,0,26*(cnt+1)*sizeof(int));
        memset(g,0,(cnt+1)*sizeof(int));
        memset(fr,0,(cnt+1)*sizeof(int));
        tot=0,cnt=lst=1;
    }
}S1,S2;
#define ls(x) a[x].ch[0]
#define rs(x) a[x].ch[1]
#define fa(x) a[x].f
#define tag(x) a[x].cltg
#define col(x) a[x].cl
struct LCT
{
    int ch[2],f,cltg,cl;
}a[N << 1];
int Q[N << 1];
int id(int x)
{
    return ls(fa(x))==x?0:1;
}
bool isrt(int x)
{
    return ls(fa(x))!=x && rs(fa(x))!=x;
}
void connect(int x,int F,int son)
{
    fa(x)=F;                           
    a[F].ch[son]=x;
}
void rot(int x)
{
    int y=fa(x),r=fa(y);
    int yson=id(x),rson=id(y);
    if (isrt(y))
        fa(x)=r; else
        connect(x,r,rson);
    connect(a[x].ch[yson^1],y,yson);
    connect(y,x,yson^1);
}
void push_tag(int x,int z)
{
    if (!x)
        return;
    tag(x)=col(x)=z;
}
void push_down(int x)
{
    if (tag(x))
    {
        push_tag(ls(x),tag(x));
        push_tag(rs(x),tag(x));
        tag(x)=0;
    }
}
void splay(int x)
{
    int g=x,k=0;
    Q[++k]=x;
    while (!isrt(g))
        g=fa(g),Q[++k]=g;
    while (k)
        push_down(Q[k--]);
    while (!isrt(x))
    {
        int y=fa(x);
        if (isrt(y))
            rot(x); else
        if (id(x)==id(y))
            rot(y),rot(x); else
            rot(x),rot(x);
    }
}
void access(int x,int r)
{
    int y;
    for (y=0;x;y=x,x=fa(x))
    {
        splay(x);
        rs(x)=y;
    }
    push_tag(y,r);
}
int Col(int x)
{
    splay(x);
    return col(x);
}
void Dfs(int u,int w)
{
    for (int i=fr[u];i;i=E[i].nxt)
    {
        int v=E[i].v;
        Dfs(v,w);
        g[u]=max(g[u],g[v]);
    }
    ans[w]+=S2.len[u]-max(S2.len[S2.pre[u]],min(g[u],S2.len[u]));
}
int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    for (int i=1;i<=n;++i)
        S1.ins(s[i]-'a');
    S1.Do_st();
    for (int i=2;i<=S1.cnt;++i)
        fa(i)=S1.pre[i];
    scanf("%d",&q);
    for (int i=1;i<=q;++i)
    {
        cin >> T[i];
        lth[i]=T[i].length();
        scanf("%d%d",&l,&r);
        e[r].push_back(mp(l,i));
    }
    int st=1;
    for (int i=1;i<=n;++i)
    {
        st=S1.tr[st][s[i]-'a'];
        access(st,i);
        for (IT it=e[i].begin();it!=e[i].end();++it)
        {
            S2.Clear();
            int l=it->first,w=it->second,s0=1,st0=1,nlen=0;
            for (int j=0;j<lth[w];++j)
                S2.ins(T[w][j]-'a');
            S2.Do_st();
            for (int j=0;j<lth[w];++j)
            {
                int c=T[w][j]-'a';
                st0=S2.tr[st0][c];
                if (!S1.tr[1][c])
                    s0=1,nlen=0; else
                    {
                        while (!S1.tr[s0][c])
                            s0=S1.pre[s0],nlen=S1.len[s0];
                        s0=S1.tr[s0][c];
                        ++nlen;
                        int tans;
                        if (Col(s0)-nlen+1>=l)
                            tans=nlen; else
                            {
                                int F=s0;
                                for (int j=20;j>=0;--j)
                                    if (S1.f[F][j] && Col(S1.f[F][j])-S1.len[S1.f[F][j]]+1<l)
                                        F=S1.f[F][j];
                                tans=max(Col(F)-l+1,S1.len[S1.f[F][0]]);
                            }
                        int k=st0;
                        for (int j=20;j>=0;--j)
                            if (S2.f[k][j] && S2.len[S2.f[k][j]]>=tans)
                                k=S2.f[k][j];
                        g[k]=max(g[k],tans);
                    }
            }
            S2.build();
            Dfs(1,w);
        }
    }
    for (int i=1;i<=q;++i)
        printf("%lld\n",ans[i]);
    return 0;
}