• CF666E 【Forensic Examination】


    题目

    每天一道(SAM)真是非常开心

    一看就是广义(SAM)+线段树合并了

    我们存好(S)串每一个前缀的终点,之后在(parent)树上倍增找到表示(S[l,r])这个子串的节点,我们用线段树合并维护好(endpos)集合,查一个区间最大值就好了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 2000005
    #define M 10000005
    #define re register
    #define LL long long
    #define mp std::make_pair
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    typedef std::pair<int,int> pii;
    struct E{int v,nxt;}e[maxn];
    char S[maxn];
    int len[maxn],fa[maxn],son[maxn][26],endpos[maxn],to[maxn],head[maxn],rt[maxn];
    int f[maxn][22],deep[maxn],loog[maxn];
    int n,m,Q,__,num,lst=1,cnt=1,tot;
    int l[M],r[M],sum[M],d[M];
    inline void add(int x,int y){e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
    inline void pushup(int x) {
    	if(sum[l[x]]>=sum[r[x]]) sum[x]=sum[l[x]],d[x]=d[l[x]];
    		else sum[x]=sum[r[x]],d[x]=d[r[x]];
    }
    int change(int now,int x,int y,int pos)	{
    	if(!now) now=++tot;
    	if(x==y) {sum[now]++;d[now]=x;return now;}
    	int mid=x+y>>1;
    	if(pos<=mid) l[now]=change(l[now],x,mid,pos);
    		else r[now]=change(r[now],mid+1,y,pos);
    	pushup(now);
    	return now;
    }
    int merge(int a,int b,int x,int y)	{
    	if(!a) return b;if(!b) return a;
    	int root=++tot;
    	if(x==y) {sum[root]=sum[a]+sum[b],d[root]=x;return root;}
    	int mid=x+y>>1;
    	l[root]=merge(l[a],l[b],x,mid),r[root]=merge(r[a],r[b],mid+1,y);
    	pushup(root);
    	return root;
    }
    inline void ins(int c,int o)	{
    	int p=++cnt,f=lst; lst=p;
    	len[p]=len[f]+1;
    	if(!o) to[++__]=p;
    		else rt[p]=change(rt[p],1,m,o);
    	while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    	if(!f) {fa[p]=1;return;}
    	int x=son[f][c];
    	if(len[f]+1==len[x]) {fa[p]=x;return;}
    	int y=++cnt;
    	len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
    	for(re int i=0;i<26;i++) son[y][i]=son[x][i];
    	while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
    }
    void dfs(int x)	{
    	for(re int i=head[x];i;i=e[i].nxt)
    	 	deep[e[i].v]=deep[x]+1,dfs(e[i].v),rt[x]=merge(rt[x],rt[e[i].v],1,m);
    }
    pii query(int now,int x,int y,int lx,int ry)
    {
    	if(lx<=x&&ry>=y) return mp(sum[now],d[now]);
    	int mid=x+y>>1;
    	if(ry<=mid) return query(l[now],x,mid,lx,ry);
    	if(lx>mid) return query(r[now],mid+1,y,lx,ry);
    	pii a=query(l[now],x,mid,lx,ry),b=query(r[now],mid+1,y,lx,ry);
    	if(a.first>=b.first) return a; return b;
    }
    int main()
    {
    	scanf("%s",S+1);n=strlen(S+1);
    	for(re int i=1;i<=n;i++) ins(S[i]-'a',0);
    	scanf("%d",&m);
    	for(re int i=1;i<=m;i++)
    	{
    		scanf("%s",S+1);n=strlen(S+1);lst=1;
    		for(re int j=1;j<=n;j++) ins(S[j]-'a',i);
    	}
    	for(re int i=2;i<=cnt;i++) add(fa[i],i);
    	deep[1]=1,dfs(1);
    	for(re int i=1;i<=cnt;i++) f[i][0]=fa[i];
    	for(re int i=2;i<=cnt;i++) loog[i]=loog[i>>1]+1;
    	for(re int j=1;j<=loog[cnt];j++)
    		for(re int i=1;i<=cnt;i++)
    			f[i][j]=f[f[i][j-1]][j-1];
    	scanf("%d",&Q);
    	int x,y,L,R;
    	while(Q--)
    	{
    		scanf("%d%d%d%d",&x,&y,&L,&R);
    		int Len=R-L+1;
    		int now=to[R];
    		for(re int i=loog[deep[now]];i>=0;--i)
    		if(f[now][i]&&len[f[now][i]]>=Len) now=f[now][i];
    		pii ans=query(rt[now],1,m,x,y);
    		if(ans.first) printf("%d %d
    ",ans.second,ans.first);
    			else printf("%d ",x),puts("0");
    	}
    	return 0;
    }
    
  • 相关阅读:
    log4net preserveLogFileNameExtension 和 watch
    BootStrap自带的图标
    git fetch批处理,遍历一个文件夹下的所有子目录,执行git fetch --all
    Recommended Settings for Tracing and Message Logging
    蜗牛—JSONJ学习ava转变
    Do you master on array in C ?
    全面推行使用智能指针的权利
    2014/08/23——OJ出现waiting...
    在Windows通过使用MinGW静态编译Assimp
    Ubuntu12.04password正确 入口的桌面(测试的恢复正常)
  • 原文地址:https://www.cnblogs.com/asuldb/p/10289797.html
Copyright © 2020-2023  润新知