zoukankan      html  css  js  c++  java
  • luoguP4094 [HEOI2016/TJOI2016]字符串

    题意

    考虑二分答案(mid),现在我们要判断(s[c...c+mid-1])是否在(s[a...b])出现过。

    首先找到(s[c...c+mid-1])所在的状态:
    建出(parent tree),从(s[1...c+mid-1])的节点(这个可以记录)用倍增向上跳到最后一个(lengeqslant mid)的节点即可,记这个节点为(now)

    之后我们要判断(now)(endpos)中是否含有([a+mid-1,b])中的某个数,我们给每个节点开个权值线段树用来维护该节点(endpos)(相当于桶),从(parent tree)向上合并线段树即可。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=500010;
    int n,m,tot,cnt,t;
    int id[maxn],root[maxn],head[maxn];
    int f[maxn][20];
    char s[maxn];
    struct edge{int to,nxt;}e[maxn<<1];
    struct Seg
    {
    	#define lc(p) (seg[p].lc)
    	#define rc(p) (seg[p].rc)
    	#define sum(p) (seg[p].sum)
    	int lc,rc,sum;
    }seg[maxn*60];
    inline int read()
    {
    	char c=getchar();int res=0,f=1;
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    	return res*f;
    }
    inline void add_edge(int u,int v)
    {
    	e[++cnt].nxt=head[u];
    	head[u]=cnt;
    	e[cnt].to=v;
    }
    inline void up(int p){sum(p)=sum(lc(p))+sum(rc(p));}
    void insert(int &p,int l,int r,int pos)
    {
    	if(!p)p=++tot;
    	sum(p)++;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(pos<=mid)insert(lc(p),l,mid,pos);
    	else insert(rc(p),mid+1,r,pos);
    }
    int query(int p,int l,int r,int ql,int qr)
    {
    	if(l>=ql&&r<=qr)return sum(p);
    	int mid=(l+r)>>1,res=0;
    	if(ql<=mid)res+=query(lc(p),l,mid,ql,qr);
    	if(qr>mid)res+=query(rc(p),mid+1,r,ql,qr);
    	return res;
    }
    int merge(int p,int q,int l,int r)
    {
    	if(!p||!q)return p+q;	
    	int x=++tot,mid=(l+r)>>1;sum(x)=sum(p)+sum(q);
    	if(l==r)return x; 
    	lc(x)=merge(lc(p),lc(q),l,mid);
    	rc(x)=merge(rc(p),rc(q),mid+1,r);
    	return x;
    }
    struct SAM
    {
    	int tot,last;
    	int fa[maxn],len[maxn];
    	int ch[maxn][30];
    	SAM(){last=tot=1;}
    	inline void add(int c)
    	{
    		int now=++tot;len[now]=len[last]+1;
    		int p=last;last=now;
    		while(p&&!ch[p][c])ch[p][c]=now,p=fa[p];
    		if(!p){fa[now]=1;return;}
    		int q=ch[p][c];
    		if(len[q]==len[p]+1)fa[now]=q;
    		else
    		{
    			int nowq=++tot;
    			len[nowq]=len[p]+1;
    			memcpy(ch[nowq],ch[q],sizeof(ch[q]));
    			fa[nowq]=fa[q];fa[q]=fa[now]=nowq;
    			while(p&&ch[p][c]==q)ch[p][c]=nowq,p=fa[p];
    		}
    	}
    }sam;
    void dfs(int x)
    {
    	for(int i=1;i<=t;i++)f[x][i]=f[f[x][i-1]][i-1];
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		f[y][0]=x;dfs(y);
    		root[x]=merge(root[x],root[y],1,n);
    	}
    }
    inline bool check(int mid,int a,int b,int c,int d)
    {
    	int now=id[c+mid-1];
    	for(int i=t;~i;i--)if(f[now][i]&&sam.len[f[now][i]]>=mid)now=f[now][i];
    	return query(root[now],1,n,a+mid-1,b)>0;
    }
    int main()
    {
    	n=read(),m=read();
    	scanf("%s",s+1);
    	id[0]=1;
    	for(int i=1;i<=n;i++)sam.add(s[i]-'a'),id[i]=sam.last,insert(root[sam.last],1,n,i);
    	for(int i=2;i<=sam.tot;i++)add_edge(sam.fa[i],i);
    	t=(int)log2(sam.tot)+1;dfs(1);
    	while(m--)
    	{
    		int a=read(),b=read(),c=read(),d=read();
    		int l=0,r=min(b-a+1,d-c+1),ans=0;
    		while(l<=r)
    		{
    			int mid=(l+r)>>1;
    			if(check(mid,a,b,c,d))ans=mid,l=mid+1;
    			else r=mid-1;
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    WebDriver(C#)之十点使用心得
    selenium加载cookie报错问题:selenium.common.exceptions.InvalidCookieDomainException: Message: invalid cookie domain
    c#和javascript函数的相互调用(ObjectForScripting 的类必须对 COM 可见。请确认该对象是公共的,或考虑向您的类添加 ComVisible 属性。)
    开源项目推荐:Qt有关的GitHub/Gitee开源项目
    Github Qt开源项目
    QCefView实现与JS的交互
    UE4 Subsystems
    Docker与k8s的恩怨情仇(八)——蓦然回首总览Kubernetes
    表格技术七十二变|手把手教你用Canvas电子表格做电子签名
    应用程序如何通过嵌入式分析技术获益
  • 原文地址:https://www.cnblogs.com/nofind/p/12056476.html
Copyright © 2011-2022 走看看