HDU 5069

HDU - 5069

求后缀与前缀的最大匹配长度

我写的很暴力

首先对于前一个字符串,直接匹配到末尾,其实接下来就是求\(fail\)树上的这段前缀上的每一个点与后一个串在\(trie\)树上的位置的最长公共前缀长度

我的做法是:将\(trie\)树树剖,依次访问\(fail\)树上的每一个节点回答询问

访问\(fail\)树上的节点前缀时就可以直接通过每经过一个点就++

对于这一段前缀的一个询问串x,令其在\(trie\)树上的末尾节点为y,我们就是找到所有的节点最深的在\(y\)对应的\(trie\)树前缀上的位置,这里我直接树剖加二分实现了

int n,m;
string s[N];

const int SIZE=N;
int End[N];
int trie[N][26],fail[N],cnt;
void clear(){
	memset(trie,0,sizeof trie);
	cnt=0;
}
int Insert(string &s){
	int p=0;
	rep(i,0,s.size()-1) {
		int x=s[i]-'A';
		if(!trie[p][x]) trie[p][x]=++cnt;
		p=trie[p][x];
	}
	return p;
}



struct Graph{
	struct Edge{
		int to,nxt;
	}e[SIZE];
	int head[N],ecnt;
	void AddEdge(int u,int v){
                e[++ecnt].to=v;e[ecnt].nxt=head[u];
		head[u]=ecnt;
	}
	void clear(){
		memset(head,0,sizeof head);
		ecnt=0;
	}
}G;

int dep[N];
int sz[N],son[N],top[N],fa[N];

void dfs1(int u){
	sz[u]=1,son[u]=-1;
	rep(i,0,25) {
		int v=trie[u][i];
		if(!v) continue;
		dep[v]=dep[u]+1;
		fa[v]=u;
		dfs1(v);
		sz[u]+=sz[v];
		if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v;
	}
}

int L[N],R[N],dfn,id[N];
void dfs2(int u,int t){
	top[u]=t;
	id[L[u]=++dfn]=u;
	if(~son[u]) dfs2(son[u],t);
	rep(i,0,25) {
		int v=trie[u][i];
		if(!v||v==son[u]) continue;
		dfs2(v,v);
	}
	R[u]=dfn;
}

void Build(){
	static queue <int> que;
	dfn=0;G.clear();
	fa[0]=-1,dfs1(0);dfs2(0,0);
	rep(i,0,25) if(trie[0][i]) {
		que.push(trie[0][i]);
		fail[trie[0][i]]=0;
	}
	while(!que.empty()){
		int u=que.front(); que.pop();
		G.AddEdge(fail[u],u);
		rep(i,0,25) {
			int &v=trie[u][i];
			if(v) {
				que.push(v);
				fail[v]=trie[fail[u]][i];
			} else v=trie[fail[u]][i];
		}
	}
}


vector <pair<int,int> > Q[N];

int sum[N];
void Add(int p,int x){
	while(p<=dfn) sum[p]+=x,p+=p&-p;
}
int Que(int p){
	int res=0;
	while(p) res+=sum[p],p-=p&-p;
	return res;
}


int Ans[N];
void dfs_getans(int u){
	Add(L[u],1);
	rep(i,0,Q[u].size()-1) {
		int x=Q[u][i].first,qid=Q[u][i].second;
		while(~x) {
			int t=Que(L[x])-Que(L[top[x]]-1);
			if(t) {//找到一个++的节点
				int p=0;
				t+=Que(L[top[x]]-1);
				drep(j,16,0) if( (p+(1<<j)<L[x]) && sum[p+(1<<j)]<t) t-=sum[p+=(1<<j)];
				p++;
				Ans[qid]=dep[id[p]];
				break;//二分这个节点的位置
			}
			x=fa[top[x]];
		}
	}
	vector <pair<int,int> > tmp;
	swap(tmp,Q[u]);
	for(int i=G.head[u];i;i=G.e[i].nxt) {
		int v=G.e[i].to;
		dfs_getans(v);
	}
	Add(L[u],-1);
}

bool ed;

int main(){
	ios::sync_with_stdio(false);
	while(cin>>n>>m) {
		clear();
		rep(i,1,n) {
			cin>>s[i];
			End[i]=Insert(s[i]);
		}
		Build();
		rep(i,1,m) {
			int x=rd(),y=rd();
			x=End[x],y=End[y];
			Q[x].push_back(make_pair(y,i));
		}
		dfs_getans(0);
		rep(i,1,m) printf("%d\n",Ans[i]);
	}
}



原文地址:https://www.cnblogs.com/chasedeath/p/12931311.html