zoukankan      html  css  js  c++  java
  • LuoguP5576 [CmdOI2019]口头禅 后缀树+线段树+暴力

    一个比较暴力的解法.  

    先对所有串建出广义后缀自动机提取出后缀树然后按照询问的右端点离线.   

    考虑插入第 $i$ 个串,那么会被 $i$ 及 $i$ 的祖先遍历到的点的表示范围会从 $[l,r] ightarrow [l,r+1]$.   

    未被遍历到的点的表示范围出现了一个“断点”,则表示范围就是 $i$ 之后最近的串 $j$,$[j,j]$.    

    将串在自动机上匹配的复杂度是 $O(len)$ 的,暴力跳 $parent$ 树均摊 $O(sqrt {len})$,总复杂度是 $O(len sqrt{len} log n)$.      

    暴力跳 $parent$ 树未必能保证复杂度正确,但好像很难卡.  

    代码: 

    #include <cstdio>
    #include <vector> 
    #include <cstring>
    #include <algorithm>   
    #define N 20004   
    #define M 400009 
    #define ll long long 
    #define pb push_back  
    #define lson now<<1 
    #define rson now<<1|1    
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;  
    int last,tot,n,Q;   
    char str[M]; 
    int an[N];  
    int ch[M<<1][2],mx[M<<1],pre[M<<1];  
    int L[N],R[N],arr[M],Min[M<<1],Max[M<<1],era[N<<2],tag[N<<2];                 
    struct que {
    	int l,r,id; 
    	que(int l=0,int r=0,int id=0):l(l),r(r),id(id){}   
    	bool operator<(const que b) const {
    		return r<b.r;   
    	}
    }; 
    vector<que>a[N];  
    void extend(int c) {
    	if(ch[last][c]) {
    		int p=last,q=ch[last][c];  
    		if(mx[q]==mx[p]+1) last=q;  
    		else {
    			int nq=++tot;  
    			mx[nq]=mx[p]+1;
    			memcpy(ch[nq],ch[q],sizeof(ch[q]));   
    			pre[nq]=pre[q],pre[q]=nq;  
    			for(;p&&ch[p][c]==q;p=pre[p]) ch[p][c]=nq;  
    			last=nq;  
    		}
    	}
    	else { 
    		int np=++tot,p=last;  
    		last=np,mx[np]=mx[p]+1;   
    		for(;p&&!ch[p][c];p=pre[p]) ch[p][c]=np;  
    		if(!p) pre[np]=1;  
    		else {
    			int q=ch[p][c]; 
    			if(mx[q]==mx[p]+1) pre[np]=q;     
    			else {
    				int nq=++tot;  
    				mx[nq]=mx[p]+1;  
    				memcpy(ch[nq],ch[q],sizeof(ch[q]));
    				pre[nq]=pre[q],pre[q]=pre[np]=nq; 
    				for(;p&&ch[p][c]==q;p=pre[p]) ch[p][c]=nq;  
    			}
    		}
    	}
    }       
    void mark(int now,int v) {
    	tag[now]=max(tag[now],v);      
    }
    void clea(int now) {
    	tag[now]=0,era[now]=1;   
    }
    void pushdown(int now) {
    	if(era[now]) {
    		clea(lson); 
    		clea(rson); 
    		era[now]=0;
    	} 
    	if(tag[now]) {
    		mark(lson,tag[now]); 
    		mark(rson,tag[now]); 
    		tag[now]=0; 
    	}
    }
    void modify(int l,int r,int now,int L,int R,int v) {
    	if(l>=L&&r<=R) {       
    		mark(now,v);   
    		return; 
    	} 
    	pushdown(now); 
    	int mid=(l+r)>>1; 
    	if(L<=mid) modify(l,mid,lson,L,R,v); 
    	if(R>mid)  modify(mid+1,r,rson,L,R,v);  
    }
    int query(int l,int r,int now,int p) {
    	if(l==r) return tag[now];  
    	pushdown(now); 
    	int mid=(l+r)>>1;  
    	if(p<=mid) return query(l,mid,lson,p); 
    	else return query(mid+1,r,rson,p);   
    }
    int trans,output[M];        
    void get(int x,int id) {
    	for(int i=x;i;i=pre[i]) {
    		if(Max[i]==id) break;  
    		if(Max[i]==id-1) {        
    			++Max[i];            
    		}
    		else {
    			Min[i]=id-1;    
    			Max[i]=id;        
    		}
    		modify(1,n,1,Min[i]+1,Max[i],mx[i]);      
    	}
    }
    void upd(int k,int id) {
    	trans=ch[trans][k];   
    	get(trans,id);   
    }
    int main() { 
    	// setIO("input"); 
    	scanf("%d%d",&n,&Q);   
    	last=tot=1; 
    	for(int i=1;i<=n;++i) {
    		scanf("%s",str+1); 
    		int len=strlen(str+1); 
    		last=1; 
    		for(int j=1;j<=len;++j) {
    			extend(str[j]-'0');   
    		}
    		L[i]=R[i-1]+1; 
    		R[i]=L[i]-1;   
    		for(int j=1;j<=len;++j) {
    			arr[++R[i]]=str[j]-'0';    
    		}     
    	}      
    	int x,y,z; 
    	for(int i=1;i<=Q;++i) {
    		scanf("%d%d",&x,&y);  
    		a[y].pb(que(x,y,i));    
    	}    
    	for(int i=1;i<=n;++i) {
    		trans=1;     
    		clea(1);    
    		for(int k=L[i];k<=R[i];++k) {
    			upd(arr[k],i);     
    		}      
    		for(int k=0;k<a[i].size();++k) {
    			que p=a[i][k];    
    			output[p.id]=query(1,n,1,p.l);       
    		}
    	}
    	for(int i=1;i<=Q;++i) {
    		printf("%d
    ",output[i]);  
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Spring Boot使用@Scheduled定时器任务
    [TaskList] 省选前板子补完计划
    [模板] 计算几何1(基础): 点/向量/线/圆/多边形/其他运算
    网络流刷题日记
    [模板] 网络流相关/最大流ISAP/费用流zkw
    11/5/2018模拟 Problem C
    11/1/2018模拟 Max
    [模板] 笛卡尔树 && RMQ
    bzoj1010-[HNOI2008]玩具装箱toy
    [模板] 斜率优化
  • 原文地址:https://www.cnblogs.com/guangheli/p/13467695.html
Copyright © 2011-2022 走看看