洛谷P5284 [十二省联考2019]字符串问题 [后缀树]

传送门


思路

\(dp_i\)表示以\(i\)结尾的\(A\)串,能达到的最长长度。

然后发现这显然可以\(i\)往自己控制的\(k\)连边,\(k\)往能匹配的\(j\)连边,就是个最长路,只要建出图来就完事了。

显然可以用数据结构得到两点之间是否有边,于是就获得了40分的好成绩。

考虑优化这个建图,字符串也就那么几个数据结构,那就后缀树吧。

有了后缀树,可以发现\(k\)会向\(k\)所在的节点的子树连边,注意不包括\(k\)自己的节点。

那么自己节点怎么办呢?把在这里的所有串拆开然后按长度排一下序即可。

然后就是用虚点优化,随便搞就好了。

这省选题好像也不难

代码先咕着,下午再写。

uptade:下午由于数组开小狂WA,怒调3小时无果,还因为size(),lower_bound()等函数炸掉而一脸懵逼……

数组就应该能开多大开多大……


代码

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define templ template<typename T>
    #define sz 1204040 
    typedef long long ll;
    typedef double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
    templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
    templ inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    char __sr[1<<21],__z[20];int __C=-1,__zz=0;
    inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
    inline void print(register int x)
    {
        if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
        while(__z[++__zz]=x%10+48,x/=10);
        while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
    }
    void file()
    {
        #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        #endif
    }
    inline void chktime()
    {
        #ifndef ONLINE_JUDGE
        cout<<(clock()-t)/1000.0<<'\n';
        #endif
    }
    #ifdef mod
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
    ll inv(ll x){return ksm(x,mod-2);}
    #else
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
    #endif
//	inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

char s[sz];
int N,n,m;
int la[sz],ra[sz],lb[sz],rb[sz];

int fa[sz],len[sz],ch[sz][27],cnt=1,lst=1;
int edp[sz];
void insert(int c)
{
    int cur=++cnt,p=lst;lst=cur;
    len[cur]=len[p]+1;
    while (p&&!ch[p][c]) ch[p][c]=cur,p=fa[p];
    if (!p) return (void)(fa[cur]=1);
    int q=ch[p][c];
    if (len[p]+1==len[q]) return (void)(fa[cur]=q);
    int t=++cnt;
    memcpy(ch[t],ch[q],sizeof(ch[q]));
    len[t]=len[p]+1;fa[t]=fa[q];
    while (p!=-1&&ch[p][c]==q) ch[p][c]=t,p=fa[p];
    fa[q]=fa[cur]=t;
}
void calcEndPos(){int x=1;drep(i,N,1) x=ch[x][s[i]-'a'+1],edp[i]=x;}

struct hh{int t,nxt;}edge[sz];
int head[sz],ecnt;
void make_edge(int f,int t){edge[++ecnt]=(hh){t,head[f]};head[f]=ecnt;}
int Fa[sz][25];
void dfs1(int x,int fa){Fa[x][0]=fa;rep(i,1,20) Fa[x][i]=Fa[Fa[x][i-1]][i-1];go(x) dfs1(edge[i].t,x);}


vector<pii>va[sz],vb[sz];
void ins(int id,int lenth,int p)
{
    drep(i,20,0) if (Fa[p][i]&&len[Fa[p][i]]>=lenth) p=Fa[p][i];
    if (id<=n) va[p].push_back(MP(lenth,id));
    else vb[p].push_back(MP(lenth,id));
}
int son[sz],cc;
int deg[sz];
struct hhh{int f,t,w,nxt;}E[sz];
int Head[sz],Ecnt;
void MakeEdge(int f,int t,int w){++deg[t];E[++Ecnt]=(hhh){f,t,w,Head[f]};Head[f]=Ecnt;}
int lastt=0;
void dfs2(int x)
{
    sort(va[x].begin(),va[x].end());
    int nxt=cc+1,las;cc+=va[x].size()+1;las=cc;
    drep(i,(int)va[x].size()-1,0) MakeEdge(nxt+i,nxt+i+1,0),MakeEdge(nxt+i,va[x][i].sec,va[x][i].fir);
    rep(i,0,(int)vb[x].size()-1)
    {
		int pos=lower_bound(va[x].begin(),va[x].end(),MP(vb[x][i].fir,-1))-va[x].begin();
        MakeEdge(vb[x][i].sec,nxt+pos,0);
    }
    go(x) dfs2(edge[i].t),MakeEdge(las,son[edge[i].t],0);
    son[x]=nxt;
}

ll dp[sz];
bool vis[sz];

void work()
{
    cin>>(s+1);
    N=strlen(s+1);
    drep(i,N,1) insert(s[i]-'a'+1);
    calcEndPos();
    rep(i,2,cnt) make_edge(fa[i],i);
    dfs1(1,0);
    int K,x,y;
    read(n);
    rep(i,1,n) read(la[i],ra[i]),ins(i,ra[i]-la[i]+1,edp[la[i]]),dp[i]=ra[i]-la[i]+1;
    read(m);
    rep(i,1,m) read(lb[i],rb[i]),ins(i+n,rb[i]-lb[i]+1,edp[lb[i]]);
    read(K);
    while (K--) read(x,y),MakeEdge(x,y+n,0);
    cc=n+m;
    dfs2(1);
    queue<int>q;
    ll ans=0;
    rep(i,1,cc) if (!deg[i]) q.push(i);
    while (!q.empty())
    {
        int x=q.front();q.pop();vis[x]=1;
        chkmax(ans,dp[x]);
        for (int i=Head[x];i;i=E[i].nxt) 
        {
            int v=E[i].t;--deg[v];chkmax(dp[v],dp[x]+E[i].w);
            if (!deg[v]) q.push(v);
        }
    }
    bool flg=1;
    rep(i,1,cc) flg&=vis[i];
    printf("%lld\n",flg?ans:-1ll);
    rep(i,1,N) s[i]='\0',edp[i]=0;
    rep(i,1,n) la[i]=ra[i]=0;
    rep(i,1,m) lb[i]=rb[i]=0;
    rep(i,1,cnt) { fa[i]=len[i]=head[i]=0; rep(j,1,26) ch[i][j]=0; }
    rep(i,1,cc) Head[i]=0,va[i].clear(),vb[i].clear(),son[i]=0,deg[i]=0,dp[i]=0,vis[i]=0;
    ecnt=cc=Ecnt=0;cnt=lst=1;
}

int main()
{
    file();
    int T;read(T);
    while (T--) work();
    return 0;
}
posted @ 2019-04-12 14:00  p_b_p_b  阅读(210)  评论(2编辑  收藏  举报