zoukankan      html  css  js  c++  java
  • CF666E Forensic Examination(广义后缀自动机+线段树合并)

    CF666E Forensic Examination(广义后缀自动机+线段树合并)

    Luogu

    给你一个串 $ S $ 以及一个字符串数组 $ T_1 ~ T_m $ , $ q $ 次询问,每次问 $ S $ 的子串 $ S[p_l,p_r] $ 在 $ T_l ~ T_r $ 中的哪个串里的出现次数最多,并输出出现次数。

    如有多解输出最靠前的那一个。

    题解时间

    SAM的毒瘤题,无论是倍增来满足长度限制,线段树合并来求区间询问,应有尽有。。。

    对于 $ T $ 串建广义SAM,之后考虑如何使得 $ S $ 在SAM上匹配时求出 $ S $ 在每个 $ T $ 的出现次数。

    很明显用线段树合并就可以搞:

    每插入 $ T_i $ 的一个字符就在 $ fin $ 上挂上一个 $ i $ 。

    然后跳parent树搞线段树合并就好。

    之后,由于每次 $ S $ 也只选中一部分,所以考虑:

    对于一组询问 $ [l,r,pl,pr] $ ,首先毫无疑问将询问挂在 $ S $ 的 $ pr $ 位上。

    之后匹配到 $ pr $ 位时,倍增跳现所处点 $ px $ 的 $ pre $ 到最上面的 $ x $ 使得 $ len[x]>=(pr-pl+1) $ 。

    然后线段树上求答案即可。

    #include<bits/stdc++.h>
    using namespace std;
    namespace RKK
    {
    const int N=1000011;
    int n,m,qaq;
    char s0[N],s1[N];int l0,l1;
    struct sumireko{int to,ne;}e[N];int he[N],ecnt;
    void addline(int f,int t){e[++ecnt].to=t;e[ecnt].ne=he[f];he[f]=ecnt;}
    int fa[N][22];
    int tcnt,rt[N],lson[N<<3],rson[N<<3];
    struct pat
    {
    	int first,second;
    	bool operator < (const pat &a)const{return second==a.second?first>a.first:second<a.second;}
    };
    pat ma[N<<3],ans[N];
    void fuckup(int px){ma[px]=max(ma[lson[px]],ma[rson[px]]);}
    void insert(int x,int &px,int pl,int pr)
    {
    	if(!px) px=++tcnt;
    	if(pl==pr)
    	{
    		ma[px].first=x,ma[px].second++;
    		return;
    	}
    	int pm=pl+pr>>1;
    	if(x<=pm) insert(x,lson[px],pl,pm);
    	else insert(x,rson[px],pm+1,pr);
    	fuckup(px);
    }
    int merge(int px,int py,int pl,int pr)
    {
    	if(!px||!py) return px|py;
    	int pz=++tcnt;
    	if(pl==pr){ma[pz]=(pat){pl,ma[px].second+ma[py].second};}
    	else
    	{
    		int pm=pl+pr>>1;
    		lson[pz]=merge(lson[px],lson[py],pl,pm);
    		rson[pz]=merge(rson[px],rson[py],pm+1,pr);
    		fuckup(pz);
    	}
    	return pz;
    }
    void query(int l,int r,int px,int pl,int pr,pat &pa)
    {
    	if(!px) return;
    	if(l<=pl&&r>=pr){pa=max(pa,ma[px]);return;}
    	int pm=pl+pr>>1;
    	if(l<=pm) query(l,r,lson[px],pl,pm,pa);
    	if(r>pm) query(l,r,rson[px],pm+1,pr,pa);
    }
    struct ques{int p,le,l,r,id;};
    vector<ques> ve[N];
    struct remilia{int tranc[26],len,pre;};
    struct sakuya
    {
    	remilia s[N];
    	int fin,size;
    	sakuya(){fin=size=1;}
    	void ins(int ch)
    	{
    		int npx,npy,lpx,lpy;
            if(s[fin].tranc[ch])
            {
                lpx=fin,lpy=s[fin].tranc[ch];
                if(s[lpy].len==s[lpx].len+1) fin=lpy;
                else
                {
                    npy=++size;
                    s[npy]=s[lpy];
                    s[npy].len=s[lpx].len+1;
                    s[lpy].pre=npy;
                    while(s[lpx].tranc[ch]==lpy)
                    {
                        s[lpx].tranc[ch]=npy;
                        lpx=s[lpx].pre;
                    }
                    fin=npy;
                }
                return;
            }
    		npx=++size;
    		s[npx].len=s[fin].len+1;
    		for(lpx=fin;lpx&&!s[lpx].tranc[ch];lpx=s[lpx].pre) s[lpx].tranc[ch]=npx;
    		if(!lpx) s[npx].pre=1;
    		else
    		{
    			lpy=s[lpx].tranc[ch];
    			if(s[lpy].len==s[lpx].len+1) s[npx].pre=lpy;
    			else
    			{
    				npy=++size;
    				s[npy]=s[lpy];
    				s[npy].len=s[lpx].len+1;
    				s[npx].pre=s[lpy].pre=npy;
    				while(s[lpx].tranc[ch]==lpy)
    				{
    					s[lpx].tranc[ch]=npy;
    					lpx=s[lpx].pre;
    				}
    			}
    		}
    		fin=npx;
    	}
    	void dfs(int x)
    	{
    		for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)
    		{
    			dfs(t),rt[x]=merge(rt[x],rt[t],1,m);
    		}
    	}
    	void work()
    	{
    		for(int i=2;i<=size;i++) fa[i][0]=s[i].pre,addline(s[i].pre,i);
    		for(int k=1;k<=21;k++)for(int i=2;i<=size;i++) fa[i][k]=fa[fa[i][k-1]][k-1];
    		dfs(1);
    		int px=1,lnow=0;
    		for(int i=1;i<=l0;i++)
    		{
    			while(px&&!s[px].tranc[s0[i]-'a']) px=s[px].pre,lnow=s[px].len;
    			if(!px) px=1,lnow=0;
    			else px=s[px].tranc[s0[i]-'a'],lnow++;
    			for(int j=0;j<ve[i].size();j++)
    			{
    				ques &qn=ve[i][j];
    				ans[qn.id].first=qn.l;
    				if(lnow<qn.le){continue;}
    				int x=px;
    				for(int k=21;k>=0;k--)if(s[fa[x][k]].len>=qn.le) x=fa[x][k];
    				query(qn.l,qn.r,rt[x],1,m,ans[qn.id]);
    			}
    		}
    	}
    }sam;
    int Iris()
    {
    	scanf("%s",s0+1),l0=strlen(s0+1);
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%s",s1+1),l1=strlen(s1+1);
    		sam.fin=1;
    		for(int j=1;j<=l1;j++) sam.ins(s1[j]-'a'),insert(i,rt[sam.fin],1,m);
    	}
    	scanf("%d",&qaq);
    	for(int i=1,l,r,x,y;i<=qaq;i++)
    	{
    		scanf("%d%d%d%d",&l,&r,&x,&y);
    		ve[y].push_back((ques){y,y-x+1,l,r,i});
    	}
    	sam.work();
    	for(int i=1;i<=qaq;i++)
    		printf("%d %d
    ",ans[i].first,ans[i].second);
    	return 0;
    }
    }
    int main(){return RKK::Iris();}
    
  • 相关阅读:
    SogouCloud.exe进程导致SQL Server服务无法启动
    SQL Server 锁实验(INSERT加锁探究)
    php如何处理大数据高并发
    PHP变量的初始化以及赋值方式介绍
    PHP数组具有的特性有哪些
    PHP中Session ID的实现原理分析
    PHP提高SESSION响应速度的方法有哪些
    PHP中Redis扩展无法加载问题
    关于PHP中依赖注入的详细介绍
    PHP中接口与抽象类的异同点有哪些
  • 原文地址:https://www.cnblogs.com/rikurika/p/12079264.html
Copyright © 2011-2022 走看看