zoukankan      html  css  js  c++  java
  • Luogu5284 [十二省联考2019]字符串问题

    在神my的督促下更一点垃圾做的垃圾题。

    Link

    Solution

    考虑用图的形式描述A与B的关系:

    (A_i)支配(B_j)就连边(A_i->B_j)

    (B_i)(A_j)的前缀就连边(B_i->A_j)

    然后设A权值为串长,B权值为0,在这个图上拓扑序即可。(ps:无限长当且仅当图中有环,反映出来就是跑完拓扑序之后图中还有点入度不为0,这样判就不需要再跑一边dfs判环了)

    但是这样暴力建边边数是(m+na imes nb)的,时间复杂度三方,喜提10pts。

    考虑优化前缀关系的连边。

    后缀树就可以很好的描述字符串的前缀关系(简化Trie)。

    所以对反串建SAM,同时记录反串每个位置对应的节点,即平时“SAM上节点endpos代表元(插入时的pos)”的反向映射。

    然后对于每个A,B串,就可以从反串(n-l+1)位置对应的节点向上跳,找到串对应的节点(u)并标记,(u)满足(len[slink[u]]<r-l+1le len[u])。这个过程可以倍增加速到(O(nlogn))

    但是直接利用SAM原图+(m)条新边跑拓扑是错的。因为SAM的节点代表的是一段长度区间,同一个节点上,可能会出现(|A_j|<|B_i|)的情况,这个时候(B_i,A_j)并不满足前缀关系连边的条件。所以还需要拆点,同一个SAM上节点拆成其对应的A,B串的多个点。

    连边就利用前缀优化连边(不知道是不是这么叫):一个节点上的串按长度排序后,原点向第一个B之前的区间连边,每个B向下一个B之前的那段区间全都连边,最后一个B(没有B就是原点)向(parent)树的子节点连边。

    然后上拓扑随便跑跑就完事了!!1

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define REP(i,a,b) for(int i=(a),_ed=(b);i<=_ed;++i)
    #define DREP(i,a,b) for(int i=(a),_ed=(b);i>=_ed;--i)
    #define pb(x) push_back((x))
    typedef long long ll;
    inline int read(){
        register int x=0,f=1;register char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
        while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
        return f?x:-x;
    }
    
    const int N=2e5+5,NN=N<<1,M=N<<2;
    int n,na,nb,m;
    char s[N];
    vector<int> E[M],S[NN];
    int tot,las,trans[NN][26],slink[NN],len[NN],pos[N];
    int tot2,ord[NN],cnt[N],fa[NN][20],rola[N],rolb[N];
    int L[NN],val[M],in[M],is[M];
    queue<int> q;ll ans,f[M];
    
    inline void extend(int c){
        int p=las,np=las=++tot;
        len[np]=len[p]+1;
        for(;p&&!trans[p][c];p=slink[p])trans[p][c]=np;
        if(!p)slink[np]=1;
        else{
    	int q=trans[p][c];
    	if(len[q]==len[p]+1)slink[np]=q;
    	else{
    	    int nq=++tot;memcpy(trans[nq],trans[q],sizeof trans[q]);
    	    len[nq]=len[p]+1;slink[nq]=slink[q];slink[np]=slink[q]=nq;
    	    for(;p&&trans[p][c]==q;p=slink[p])trans[p][c]=nq;
    	}
        }
    }
    
    inline int find(int p,int l){DREP(i,19,0)if(len[fa[p][i]]>=l)p=fa[p][i];return p;}
    inline void add(int u,int v){++in[v];E[u].pb(v);}
    inline bool cmp(const int &a,const int &b){return val[a]==val[b]?is[a]<is[b]:val[a]<val[b];}
    
    inline void work(){
        scanf("%s",s+1);n=strlen(s+1);
        DREP(i,n,1)extend(s[i]-'a'),pos[n-i+1]=las;
        REP(i,1,tot)++cnt[len[i]];
        REP(i,1,n)cnt[i]+=cnt[i-1];
        DREP(i,tot,1)ord[cnt[len[i]]--]=i;
        REP(i,1,tot){
    	int u=ord[i];fa[u][0]=slink[u];
    	for(int i=1;fa[u][i-1];++i)fa[u][i]=fa[fa[u][i-1]][i-1];
        }
        tot2=tot;
        REP(i,1,na=read()){
    	int l=n-read()+1,r=n-read()+1;
    	int p=find(pos[l],l-r+1);
    	val[rola[i]=++tot2]=l-r+1;S[p].pb(tot2);
    	is[tot2]=1;
        }
        REP(i,1,nb=read()){
    	int l=n-read()+1,r=n-read()+1;
    	int p=find(pos[l],l-r+1);
    	val[rolb[i]=++tot2]=l-r+1;S[p].pb(tot2);
        }
        REP(i,1,m=read()){
    	int u=rola[read()],v=rolb[read()];
    	add(u,v);
        }
        REP(i,1,tot){
    	sort(S[i].begin(),S[i].end(),cmp);
    	int lst=i;
    	REP(j,0,S[i].size()-1){
    	    int u=S[i][j];add(lst,u);
    	    if(!is[u])lst=u,val[u]=0;
    	}
    	L[i]=lst;
        }
        REP(i,2,tot)add(L[slink[ord[i]]],ord[i]);
        REP(i,1,tot2)if(!in[i])q.push(i);
        while(!q.empty()){
    	int u=q.front();q.pop();
    	f[u]+=val[u];
    	REP(i,0,E[u].size()-1){
    	    int v=E[u][i];
    	    f[v]=max(f[v],f[u]);
    	    if(!--in[v])q.push(v);
    	}
        }
        REP(i,1,tot2){
    	ans=max(ans,f[i]);
    	if(in[i])return puts("-1"),void();
        }
        printf("%lld
    ",ans);
    }
    
    inline void clear(){
        memset(pos+1,0,sizeof(int)*n);
        memset(cnt+1,0,sizeof(int)*n);
        memset(rola+1,0,sizeof(int)*na);
        memset(rolb+1,0,sizeof(int)*nb);
        REP(i,1,tot){
    	slink[i]=len[i]=L[i]=ord[i]=0;
    	S[i].clear();
    	memset(fa[i],0,sizeof(fa[0]));
    	memset(trans[i],0,sizeof(trans[0]));
        }
        tot=las=1;
        REP(i,1,tot2){
    	val[i]=in[i]=is[i]=f[i]=0;
    	E[i].clear();
        }
        ans=0;
        q=queue<int>();
    }
    
    int main(){
        //freopen("in.in","r",stdin);
        REP(i,1,read())
    	clear(),
    	work();
        return 0;
    }
    
    
  • 相关阅读:
    idea系列---【测试一段代码执行时间,每次都得复制粘贴,idea如何设置自定义模板代码?】
    我爱java系列---【java8时间类Instant】
    我爱java系列---【Java比较浮点数的正确方式】
    idea系列---【idea常用快捷键大全】
    linux系列---【linux系统如何创建一个软/硬连接?】
    vue系列---【vue项目如何使用element-ui的弹框提示?】
    vue系列---【vue项目中element-ui如何实现在登陆之前进行预校验?校验通过才允许调后台接口】
    vue系列---【vue项目中element-ui如何实现点击重置按钮,重置表单数据?】
    vue系列---【element-ui如何给表单添加参数验证?】
    面对对象的随笔
  • 原文地址:https://www.cnblogs.com/fruitea/p/12392921.html
Copyright © 2011-2022 走看看