[十二省联考2019]字符串问题 后缀自动机_拓扑排序_最长路_倍增

[十二省联考2019]字符串问题 后缀自动机_拓扑排序_最长路_倍增

真的不太好写,一定要开 long long

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue> 
#include <vector> 
#define setIO(s) freopen(s".in","r",stdin)// ,freopen(s".out","w",stdout) 
#define maxn 1500001 
using namespace std;
char str[maxn]; 
int debug; 
int length,na,nb,m;  
namespace SAM{
    #define N 29 
    #define ll long long 
    #define L l=length-l+1
    #define R r=length-r+1 
    int last,tot;     
    vector<int>ed[maxn];        
    int la[maxn],ra[maxn],h[maxn];     
    int ch[maxn][N],dis[maxn]; 
    int f[maxn],trace[maxn],mk[maxn],pos[maxn];  
    int F[24][maxn];     
    int head[maxn],to[maxn],nex[maxn],edges; 
    int ge[maxn]; 
    int vis[maxn]; 
    int trc; 
    queue<int>Q; 
    int du[maxn]; 
    long long DP[maxn]; 
    int idx[maxn]; 
    int cmp(int i,int j){   if(h[i]==h[j]) return i>j; return h[i]<h[j];         }
    void add(int u,int v){
        nex[++edges] = head[u],head[u]=edges,to[edges]=v;    
        mk[edges]=0;   
        //if(!debug) printf("%d %d\n",u,v); 
    }
    //SAM of S 
    void ins(int c,int i){          
        int np = ++tot, p = last; last = np; dis[np] = i; 
   	    while(p && !ch[p][c]) ch[p][c] = np, p = f[p];     
	    if(!p) f[np] = 1;
	    else {      
	        int q = ch[p][c];	
	        if(dis[q] == dis[p] + 1) f[np] = q;
	        else {
		        int nq = ++tot; 
		        dis[nq] = dis[p] + 1; 
                memcpy(ch[nq],ch[q],sizeof(ch[q])); 
		        f[nq] = f[q], f[np] = f[q] = nq;   
		        while(p && ch[p][c] == q) ch[p][c] = nq,p = f[p]; 
	        }
	    }
        trace[i] = np; 
    } 
    void DFS(int u){           
        F[0][u]=f[u];
        for(int i=1;i<24;++i) F[i][u]=F[i-1][F[i-1][u]];  
        int sz=ed[u].size(); 
        for(int i=0;i<sz;++i) DFS(ed[u][i]); 
        ed[u].clear(); 
    }    
    void build(){
        int l,r;scanf("%d",&na);
        for(int i=1;i<=na;++i){
            scanf("%d%d",&l,&r); L;R; swap(l,r); 
            la[i]=l,ra[i]=r,h[i]=r-l+1;   
        } scanf("%d",&nb); 
        for(int i=1;i<=nb;++i)  {
            scanf("%d%d",&l,&r); L;R; swap(l,r); 
            la[i+na]=l,ra[i+na]=r,h[i+na]=r-l+1;  
        }for(int i=2;i<=tot;++i) ed[f[i]].push_back(i); 
        trc=tot; 
        DFS(1);      
        for(int i=1;i<=na+nb;++i) {
            int p=trace[ra[i]];  
            for(int j=23;j>=0;--j) 
                if(dis[F[j][p]] >= h[i]) 
                    p=F[j][p];    
            if(dis[p]==h[i]) 
                pos[i]=p;             
            else 
                ed[p].push_back(i); 
        }
    }
    void sol(){
        int nn=tot; 
        for(int i=2;i<=nn;++i){   
            if(ed[i].size()==0){       
                add(f[i],i);           
                continue; 
            }
            int p=0;                
            int sz=ed[i].size();        
            for(int j=0;j<sz;++j) ge[++p]=ed[i][j];           //  
            sort(ge+1,ge+1+p,cmp);                           //将该点对应字符串按长度排序       
            int lst=f[i]; 
            for(int j=1;j<=p;++j) {            
                add(lst,++tot); 
                dis[tot] = h[ge[j]];   
                pos[ge[j]]=tot;  
                lst=tot; 
            }
            add(pos[ge[p]],i); 
            ed[i].clear(); 
        }
    }
    void get(){
        int a,b; 
        scanf("%d%d",&a,&b); 
        add(pos[a],pos[b+na]);   
        mk[edges]=1;  
    }     
    void solve(){
        Q.push(1); 
        du[1]=0; 
        long long  ans=0; 
        for(int i=1;i<=edges;++i) ++du[to[i]]; 
        while(!Q.empty()){
            int u=Q.front(); Q.pop(); 
            for(int i=head[u];i;i=nex[i]){
                --du[to[i]];                       
                long long ed=DP[u]+dis[to[i]]-(mk[i]?0:dis[u]); 
                DP[to[i]]=max(DP[to[i]],ed);                           
                if(du[to[i]]==0) Q.push(to[i]); 
            }
        }    
        for(int i=1;i<=tot;++i) if(du[i]!=0) {
            printf("-1\n"); 
            return; 
        }
        for(int i=1;i<=na;++i)  ans=max(ans,DP[pos[i]]);      
        printf("%lld\n",ans);     
    }
    void init(){
        for(int i=1;i<=tot;++i) DP[i]=0; 
        for(int i=1;i<=tot;++i) dis[i]=0;    
        for(int i=1;i<=edges;++i) mk[i]=0;        
        for(int i=1;i<=tot;++i) head[i]=0;  
        for(int i=0;i<=tot;++i) du[i]=0;      
        for(int i=1;i<=trc;++i) for(int j=0;j<=22;++j) F[j][i]=0; 
        for(int i=1;i<=trc;++i) memset(ch[i],0,sizeof(ch[i]));     
        last=tot=1,edges=0;     
    }
};
int main(){
    //setIO("string9");   
    int T; 
    scanf("%d",&T);   
    while(T--){    
        debug=T; 
        SAM::last=SAM::tot=1;            
        scanf("%s",str+1),length=strlen(str+1);             
        for(int i=length;i;--i) SAM::ins(str[i]-'a',length-i+1);          
        SAM::trc=SAM::tot; 
        SAM::build();   
        SAM::sol(); 
        scanf("%d",&m); 
        for(int i=1;i<=m;++i) SAM::get();     
        SAM::solve(); 
        SAM::init(); 
    }
    return 0; 
}

  

posted @ 2019-04-09 20:34 EM-LGH 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值