zoukankan      html  css  js  c++  java
  • CF666E-Forensic Examination【广义SAM,线段树合并】

    正题

    题目链接:https://www.luogu.com.cn/problem/CF666E


    解题思路

    给出一个串(S)(n)个串(T_i)(m)次询问(S_{asim b})(T_{lsim r})中出现的最多次数并且输出这个串的编号。

    (1leq |s|leq 5 imes 10^5,sum T_ileq 5 imes 10^4,1leq mleq 5 imes 10^5)


    解题思路

    (S)(T)丢一起跑一个广义(SAM)

    两个串包含当且仅当他们在(SAM)上对应节点是父子,所以直接对于每个节点开一个线段树,然后(T)的每个位置对应编号加一。

    对于询问(S)子串直接倍增跳到对应位置然后用线段树合并上来的东西求答案就好了。


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e6+2e5+10,S=19;
    int answ,ansv;
    struct SegTree{
    	int cnt,w[N*20],v[N*20],ls[N*20],rs[N*20];
    	void PushUp(int x,int L,int R){
    		w[x]=-1;
    		if(w[ls[x]]>w[x])w[x]=w[ls[x]],v[x]=max(v[ls[x]],L);
    		if(w[rs[x]]>w[x])w[x]=w[rs[x]],v[x]=v[rs[x]];
    		return;
    	}
    	void Change(int &x,int L,int R,int pos){
    		if(!x)x=++cnt;
    		if(L==R){w[x]++;v[x]=L;return;}
    		int mid=(L+R)>>1;
    		if(pos<=mid)Change(ls[x],L,mid,pos);
    		else Change(rs[x],mid+1,R,pos);
    		PushUp(x,L,R);return;
    	}
    	void Ask(int x,int L,int R,int l,int r){
    		if(!x){if(answ<0)answ=0,ansv=l;return;}
    		if(L==l&&R==r){if(answ<w[x])answ=w[x],ansv=v[x];return;}
    		int mid=(L+R)>>1;
    		if(r<=mid)Ask(ls[x],L,mid,l,r);
    		else if(l>mid)Ask(rs[x],mid+1,R,l,r);
    		else Ask(ls[x],L,mid,l,mid),Ask(rs[x],mid+1,R,mid+1,r);
    	}
    	int Merge(int x,int y,int L,int R){
    		if(!x||!y)return x+y;int p=++cnt;
    		if(L==R){w[p]=w[x]+w[y];v[p]=L;return p;}
    		int mid=(L+R)>>1; 
    		ls[p]=Merge(ls[x],ls[y],L,mid);
    		rs[p]=Merge(rs[x],rs[y],mid+1,R);
    		PushUp(p,L,R);return p;
    	}
    }T;
    struct node{
    	int to,next;
    }a[N];
    int n,m,l,tot,f[N][S+1],rt[N],ls[N];
    int cnt,len[N],ch[N][26],fa[N],pos[N];
    char s[N];
    void addl(int x,int y){
    	a[++tot].to=y;
    	a[tot].next=ls[x];
    	ls[x]=tot;return;
    }
    int Insert(int p,int c){
    	if(ch[p][c]){
    		int q=ch[p][c];
    		if(len[p]+1==len[q])return q;
    		else{
    			int nq=++cnt;len[nq]=len[p]+1;
    			memcpy(ch[nq],ch[q],sizeof(ch[nq]));
    			fa[nq]=fa[q];fa[q]=nq;
    			for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
    			return nq;
    		}
    	}
    	int np=++cnt;
    	len[np]=len[p]+1;
    	for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
    	if(!p)fa[np]=1;
    	else{
    		int q=ch[p][c];
    		if(len[p]+1==len[q])fa[np]=q;
    		else{
    			int nq=++cnt;len[nq]=len[p]+1;
    			memcpy(ch[nq],ch[q],sizeof(ch[nq]));
    			fa[nq]=fa[q];fa[q]=fa[np]=nq;
    			for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
    		}
    	}
    	return np;
    }
    void dfs(int x){
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;
    		f[y][0]=x;dfs(y);
    		rt[x]=T.Merge(rt[x],rt[y],1,n);
    	}
    	return;
    }
    int GetPos(int l,int r){
    	int x=pos[r];
    	for(int i=S;i>=0;i--)
    		if(len[f[x][i]]>=r-l+1)x=f[x][i];
    	return x;
    }
    int main()
    {
    	scanf("%s",s+1);
    	l=strlen(s+1);cnt=1;
    	for(int i=1,x=1;i<=l;i++){
    		x=Insert(x,s[i]-'a');
    		pos[i]=x;
    	}
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%s",s+1);
    		int x=1,l=strlen(s+1);
    		for(int j=1;j<=l;j++){
    			x=Insert(x,s[j]-'a');
    			T.Change(rt[x],1,n,i);
    		}
    	}
    	for(int i=2;i<=cnt;i++)addl(fa[i],i);
    	dfs(1);
    	for(int j=1;j<=S;j++)
    		for(int i=1;i<=cnt;i++)
    			f[i][j]=f[f[i][j-1]][j-1];
    	scanf("%d",&m);
    	while(m--){
    		int a,b,l,r;
    		scanf("%d%d%d%d",&l,&r,&a,&b);
    		int x=GetPos(a,b);answ=-1;ansv=0;
    		T.Ask(rt[x],1,n,l,r);
    		printf("%d %d
    ",ansv,answ);
    	}
    	return 0;
    }
    
  • 相关阅读:
    React元素渲染
    初识JSX
    微信小程序复制文本到剪切板
    微信小程序报错request:fail url not in domain list
    小程序,通过自定义编译条件,模拟推荐人功能
    积分抵扣逻辑
    微信小程序 switch 样式
    tomcat 配置开启 APR 模式
    tomcat8 传输json 报错 Invalid character found in the request target. The valid characters are defined in RFC 3986
    c++数组初始化误区
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15174866.html
Copyright © 2011-2022 走看看