zoukankan      html  css  js  c++  java
  • 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]);
    	}
    }
    
    
    
    
  • 相关阅读:
    Flask request接口获取参数
    python踩坑系列之导入包时下划红线及报错“No module named”问题
    报表测试方法与注意事项
    如何查看队列被某个应用消费
    Jinkins自动构建
    Python3字典排序
    【Win10】【译】提交 UWP 应用时遇到意料之外的语言?
    【Win10】探索 Windows 10 10586 之 JumpList(跳转列表)
    【Win10】页面导航的实现
    【Win10】使用 ValidationAttribute 实现数据验证
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12931311.html
Copyright © 2011-2022 走看看