zoukankan      html  css  js  c++  java
  • codeforces #305 E Mike and friends

    原问题可以转化为:给定第k个字符串,求它在L-R的字符串里作为子串出现了多少次

    定义子串为字符串的某个前缀的某个后缀(废话)

    等价于我们把一个字符串插入到trie里,其过程中每个经过的节点和其向上的fail链上的点都是该字符串的子串

    又因为对于一条fail链,u向上能访问到v当前仅当u在v的子树内

    那么原问题又变成了:

    将L-R个字符串按照上述方法插入到trie中并将经过的节点的val值增加

    求第k个字符串对应的单词节点在fail树上的子树的权值和

    又因为查询的信息满足区间可减性,所以我们可以建出fail树

    对fail树用可持久化线段树维护DFS序 完成单点修改和子树查询

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    using namespace std;
    
    const int maxn=500010;
    int n,m,sum=0;
    int L,R,k;
    int pos[maxn];
    int rt[maxn];
    char s[maxn];
    queue<int>Q;
    
    int h[maxn],cnt=0;
    int A[maxn],B[maxn],tot=0;
    struct edge{
    	int to,next;
    }G[maxn<<1];
    
    void add(int x,int y){++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;}
    void Get_DFS(int u){
    	A[u]=++tot;
    	for(int i=h[u];i;i=G[i].next)Get_DFS(G[i].to);
    	B[u]=tot;
    }
    
    struct Seg_Tree{
    	int L,R,v;
    }t[11000010];
    
    void build(int &o,int L,int R){
    	o=++sum;
    	if(L==R)return;
    	int mid=(L+R)>>1;
    	build(t[o].L,L,mid);
    	build(t[o].R,mid+1,R);
    }
    void modify(int &o,int L,int R,int p){
    	t[++sum]=t[o];o=sum;
    	if(L==R){t[o].v++;return;}
    	int mid=(L+R)>>1;
    	if(p<=mid)modify(t[o].L,L,mid,p);
    	else modify(t[o].R,mid+1,R,p);
    	t[o].v=t[t[o].L].v+t[t[o].R].v;
    }
    int ask(int o,int L,int R,int x,int y){
    	if(L>=x&&R<=y)return t[o].v;
    	int mid=(L+R)>>1;
    	if(y<=mid)return ask(t[o].L,L,mid,x,y);
    	else if(x>mid)return ask(t[o].R,mid+1,R,x,y);
    	else return ask(t[o].L,L,mid,x,y)+ask(t[o].R,mid+1,R,x,y);
    }
    
    struct Trie{
    	int cnt;
    	int t[maxn][26];
    	int fail[maxn],fa[maxn];
    	void init(){
    		cnt=1;fail[0]=1;
    		for(int i=0;i<26;++i)t[0][i]=1;
    	}
    	int insert(){
    		int len=strlen(s+1);
    		int now=1;
    		for(int i=1;i<=len;++i){
    			int id=s[i]-'a';
    			if(!t[now][id])t[now][id]=++cnt,fa[t[now][id]]=now;
    			now=t[now][id];
    		}return now;
    	}
    	void build_fail(){
    		Q.push(1);fail[1]=0;
    		while(!Q.empty()){
    			int u=Q.front();Q.pop();
    			for(int i=0;i<26;++i){
    				if(t[u][i]){
    					int k=fail[u];
    					while(!t[k][i])k=fail[k];
    					fail[t[u][i]]=t[k][i];
    					add(t[k][i],t[u][i]);
    					Q.push(t[u][i]);
    				}
    			}
    		}return;
    	}
    	void UPD(){
    		build(rt[0],1,cnt);
    		for(int i=1;i<=n;++i){
    			rt[i]=rt[i-1];
    			for(int j=pos[i];j!=1;j=fa[j]){
    				modify(rt[i],1,cnt,A[j]);
    			}
    		}return;
    	}
    }AC;
    
    int main(){
    	scanf("%d%d",&n,&m);
    	AC.init();
    	for(int i=1;i<=n;++i){
    		scanf("%s",s+1);
    		pos[i]=AC.insert();
    	}AC.build_fail();Get_DFS(1);AC.UPD();
    	for(int i=1;i<=m;++i){
    		scanf("%d%d%d",&L,&R,&k);
    		printf("%d
    ",ask(rt[R],1,AC.cnt,A[pos[k]],B[pos[k]])-ask(rt[L-1],1,AC.cnt,A[pos[k]],B[pos[k]]));
    	}return 0;
    }
    

      

    即可

  • 相关阅读:
    配置高并发jdbc连接池
    java中的sleep()和wait()的区别
    程序员必知的8大排序(三)-------冒泡排序,快速排序(java实现)
    转HashMap Hashtable区别
    chrome 常用快捷操作
    sublime Text 常用操作
    flash 右键菜单隐藏与修改
    As3.0 视频缓冲、下载总结
    flash cs6 更新到Flash player15.0 及Air 更新方法
    As3.0 Interface 与类的使用
  • 原文地址:https://www.cnblogs.com/joyouth/p/5352844.html
Copyright © 2011-2022 走看看