• bzoj 3881 [Coci2015]Divljak fail树+树链的并


    题目大意

    Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的。
    接下来会发生q个操作,操作有两种形式:
    “1 P”,Bob往自己的集合里添加了一个字符串P。
    “2 x”,Alice询问Bob,集合T中有多少个字符串包含串S_x。(我们称串A包含串B,当且仅当B是A的子串)
    Bob遇到了困难,需要你的帮助。

    分析

    按S建好trie图,跑出fail树
    fail树+树链的并
    fail树中在一个点子树中的点字符串包含他
    于是我们用树链的并修改
    用子树求

    注意

    写rmqLCA不写init()
    而且rmqLCA是每次访问都加一次那种序
    别跟周围的什么dfn序,入栈出栈序搞混了
    还过样例又过自测的5个点数据
    什么心态

    solution

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int M=2000007;
    
    inline int rd(){
    	int x=0;bool f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(;isdigit(c);c=getchar()) x=x*10+c-48;
    	return f?x:-x;
    }
    
    int n,m;
    char s[M];
    int tot=0;
    int ch[M][26];
    int q[M];
    int pre[M];
    int id[M];
    int st[M],ed[M],tdfn;
    int g[M],te;
    struct edge{int y,nxt;}e[M];
    int a[M<<1][23];
    int ln[M<<1],T;
    int pos[M];
    
    int c[M];
    inline int lb(int x){return x&-x;}
    void add(int x,int d){
    	for(;x<=tdfn;x+=lb(x)) c[x]+=d;
    }
    int get(int x,int y){
    	int res=0;
    	for(;y>0;y-=lb(y)) res+=c[y];
    	for(x--;x>0;x-=lb(x)) res-=c[x];
    	return res;
    }
    
    void addedge(int x,int y){
    	e[++te].y=y;e[te].nxt=g[x];g[x]=te;
    }
    
    void ins(int ii){
    	int len=strlen(s+1);
    	int x=0,i,d;
    	for(i=1;i<=len;i++){
    		d=s[i]-'a';
    		if(ch[x][d]) x=ch[x][d];
    		else x=ch[x][d]=++tot;
    	}
    	id[ii]=x;
    }
    
    void getfail(){
    	int h=0,t=1,x,i;
    	q[1]=0;
    	while(h^t){
    		x=q[++h];
    		for(i=0;i<26;i++){
    			if(ch[x][i]){
    				pre[ch[x][i]]=x?ch[pre[x]][i]:0;
    				q[++t]=ch[x][i];
    			}
    			else ch[x][i]=x?ch[pre[x]][i]:0;
    		}
    	}
    }
    
    void dfs(int x){
    	a[pos[x]=++T][0]=x;
    	st[x]=++tdfn;
    	int p,y;
    	for(p=g[x];p;p=e[p].nxt){
    		dfs(e[p].y);
    		a[++T][0]=x;
    	}
    	ed[x]=tdfn;
    }
    
    int pt[M],num;
    bool cmp(int x,int y){
    	return st[x]<st[y];
    }
    
    void gao(){
    	int i,x=0,d;
    	int len=strlen(s+1);
    	for(i=1;i<=len;i++){
    		d=s[i]-'a';
    		x=ch[x][d];
    		pt[++num]=x;
    	}
    }
    
    int mn(int x,int y){
    	return st[x]<st[y]?x:y;
    }
    
    void init(){
    	int i,j,l;
    	for(i=2;i<=T;i++) ln[i]=ln[i>>1]+1;
    	for(i=T;i>0;i--){
    		l=ln[T-i+1];
    		for(j=1;j<=l;j++) a[i][j]=mn(a[i][j-1],a[i+(1<<j-1)][j-1]);
    	}
    }
    
    int LCA(int x,int y){
    	x=pos[x], y=pos[y];
    	if(x>y) swap(x,y);
    	int l=ln[y-x+1];
    	return mn(a[x][l],a[y-(1<<l)+1][l]);
    }
    
    int main(){
    	int i,kd,x;
    	n=rd();
    	for(i=1;i<=n;i++){
    		scanf("%s",s+1);
    		ins(i);
    	}
    	getfail();
    	for(i=1;i<=tot;i++) addedge(pre[i],i);
    	dfs(0);
    	init();
    	
    	m=rd();
    	while(m--){
    		kd=rd();
    		if(kd==1){
    			scanf("%s",s+1);
    			num=0;
    			gao();
    			sort(pt+1,pt+num+1,cmp);
    			for(i=1;i<=num;i++)
    				add(st[pt[i]],1);
    			for(i=2;i<=num;i++)
    				add(st[LCA(pt[i-1],pt[i])],-1);
    		}
    		else{
    			x=rd();
    			printf("%d
    ",get(st[id[x]],ed[id[x]]));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    移动开发iOS&Android对比学习--异步处理
    PHP中文乱码解决办法[转]
    在eclipse里配置Android ndk环境 适用于windows mac 和linux[转]
    android在更新ADT以后报java.lang.NoClassDefFound的解决办法
    在Mac OS下配置PHP开发环境
    在iOS中使用百度地图
    简单说明CentOS源码安装程序
    SecureFXPortable中文乱码
    从Linux下载文件到Windows没有换行问题
    从Windows复制文件到Linux显示乱码问题
  • 原文地址:https://www.cnblogs.com/acha/p/6425243.html
Copyright © 2020-2023  润新知