zoukankan      html  css  js  c++  java
  • LOJ #3049. 「十二省联考 2019」字符串问题

    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 ightarrow A),(B ightarrow 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
    ",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();
    }
    
  • 相关阅读:
    程序的链接
    Graphviz 画图的一些总结
    C表达式中的汇编指令
    epoll(2) 源码分析
    epoll(2) 使用及源码分析的引子
    eventfd(2) 结合 select(2) 源码分析
    poll(2) 源码分析
    select 源码分析
    kfifo
    程序的机器级表示:寻址方式、指令及栈的运行机制
  • 原文地址:https://www.cnblogs.com/suika/p/10666961.html
Copyright © 2011-2022 走看看