• bzoj 3145 [Feyat cup 1.5]Str


    权限题

    这题暴力就是两个串分别枚举点(i,j),假设这两个点不同,那么剩下的部分就是尽量越长越好,所以这部分答案就是第一个串(i-1)前缀和第二个串(j-1)前缀的(lcs)+第一个串(i+1)后缀和第二个串(j+1)后缀的(lcp)+1

    考虑把两个串接起来,中间用个没用过的字符隔开,那么两个串前缀的(lcs)就可以先在前缀树上找到对应的两个点,然后就是两点(lca)(length).后缀的(lcp)也类似.那么答案就是(max (lcs(a_{i-1},a_{j-1})+lcp(b_{i+1},b_{j+1}))),其中(a_i)为某前缀在前缀树上对应点,(b_i)为后缀在后缀树上对应点

    所以这个问题变成了询问所有点对在两棵树上lca深度和的最大值.可以dfs第一棵树,然后处理第一棵树上lca为(x)的点对,每次把儿子内点在第二棵树的信息合并过来,就能求解.首先,两个子树合并,为了保证复杂度,需要启发式合并,然后在合并时算贡献.现在就是要知道某个点和一个点集内点在第二棵树上的lca最大深度,容易发现一定和dfs序相邻的点lca最深.所以一个点维护的是子树内点在第二棵树上以dfs序为关键字的set,每次二分查找前驱后继即可

    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    #define db double
    
    using namespace std;
    const int N=2e5+10;
    LL rd()
    {
    	LL x=0,w=1;char ch=0;
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*w;
    }
    struct SAM
    {
    	int fa[N<<1],ch[N<<1][28],len[N<<1],la,tt;
    	int ps[N],px[N<<1],sz[N<<1],de[N<<1],hs[N<<1],top[N<<1],dfn[N<<1],ti;
    	vector<int> e[N<<1];
    	SAM(){la=tt=1;}
    	void extd(int cx,int ii)
    	{
    		int np=++tt,p=la;
    		len[np]=len[p]+1,ps[ii]=np,px[np]=ii,la=np;
    		while(!ch[p][cx]) ch[p][cx]=np,p=fa[p];
    		if(!p) fa[np]=1;
    		else
    		{
    			int q=ch[p][cx];
    			if(len[q]==len[p]+1) fa[np]=q;
    			else
    			{
    				int nq=++tt;
    				fa[nq]=fa[q],len[nq]=len[p]+1;
    				memcpy(ch[nq],ch[q],sizeof(ch[q]));
    				fa[np]=fa[q]=nq;
    				while(ch[p][cx]==q) ch[p][cx]=nq,p=fa[p];
    			}
    		}
    	}
    	void dfs1(int x)
    	{
    		sz[x]=1;
    		vector<int>::iterator it;
    		for(it=e[x].begin();it!=e[x].end();++it)
    		{
    			int y=*it;
    			de[y]=de[x]+1,dfs1(y);
    			sz[x]+=sz[y],hs[x]=sz[hs[x]]>sz[y]?hs[x]:y;
    		}
    	}
    	void dfs2(int x,int ntp)
    	{
    		dfn[x]=++ti,top[x]=ntp;
    		if(hs[x]) dfs2(hs[x],ntp);
    		vector<int>::iterator it;
    		for(it=e[x].begin();it!=e[x].end();++it)
    		{
    			int y=*it;
    			if(y==hs[x]) continue;
    			dfs2(y,y);
    		}
    	}
    	void inii()
    	{
    		for(int i=2;i<=tt;++i) e[fa[i]].push_back(i);
    		dfs1(1),dfs2(1,1);
    	}
    	int glca(int x,int y)
    	{
    		while(top[x]!=top[y])
    		{
    			if(de[top[x]]<de[top[y]]) swap(x,y);
    			x=fa[top[x]];
    		}
    		return de[x]<de[y]?x:y;
    	}
    }t1,t2;
    int n,m,ans;
    char cc[N];
    struct node
    {
    	int x;
    	bool operator < (const node &bb) const {return t2.dfn[x]<t2.dfn[bb.x];}
    };
    multiset<node> s1[N<<1],s2[N<<1];
    multiset<node>::iterator i1,i2,ft,nt,zr;
    int id[N<<1],tot;
    void dfs(int x)
    {
    	vector<int>::iterator it;
    	id[x]=x;
    	if(t1.px[x])
    	{
    		if(t1.px[x]+1<=n+1) s1[id[x]].insert((node){t2.ps[t1.px[x]+2]});
    		else if(t1.px[x]+1>n+2&&t1.px[x]+2<=n+m+2) s2[id[x]].insert((node){t2.ps[t1.px[x]+2]});
    	}
    	for(it=t1.e[x].begin();it!=t1.e[x].end();++it)
    	{
    		int y=*it;
    		dfs(y);
    		if(s1[id[x]].size()+s2[id[x]].size()<s1[id[y]].size()+s2[id[y]].size()) swap(id[x],id[y]);
    		bool fg1=!s1[id[x]].empty(),fg2=!s2[id[x]].empty();
    		if(fg2)
    		{
    			for(i1=s1[id[y]].begin();i1!=s1[id[y]].end();++i1)
    			{
    				int xx=(*i1).x;
    				nt=s2[id[x]].upper_bound(*i1);
    				if(nt!=s2[id[x]].begin()) ft=--nt,++nt;
    				else ft=zr;
    				if((*ft).x) ans=max(ans,t1.len[x]+t2.len[t2.glca((*ft).x,xx)]+1);
    				if(nt!=s2[id[x]].end()) ans=max(ans,t1.len[x]+t2.len[t2.glca((*nt).x,xx)]+1);
    			}
    		}
    		if(fg1)
    		{
    			for(i2=s2[id[y]].begin();i2!=s2[id[y]].end();++i2)
    			{
    				int xx=(*i2).x;
    				nt=s1[id[x]].upper_bound(*i2);
    				if(nt!=s1[id[x]].begin()) ft=--nt,++nt;
    				else ft=zr;
    				if((*ft).x) ans=max(ans,t1.len[x]+t2.len[t2.glca((*ft).x,xx)]+1);
    				if(nt!=s1[id[x]].end()) ans=max(ans,t1.len[x]+t2.len[t2.glca((*nt).x,xx)]+1);
    			}
    		}
    		for(i1=s1[id[y]].begin();i1!=s1[id[y]].end();++i1) s1[id[x]].insert(*i1);
    		for(i2=s2[id[y]].begin();i2!=s2[id[y]].end();++i2) s2[id[x]].insert(*i2);
    	}
    }
    
    int main()
    {
    	cc[1]='|';
    	scanf("%s",cc+2);
    	n=strlen(cc+2);
    	cc[n+2]='{';
    	scanf("%s",cc+n+3);
    	m=strlen(cc+n+3);
    	for(int i=1;i<=n+m+2;++i) t1.extd(cc[i]-'a',i);
    	t1.inii();
    	for(int i=n+m+2;i;--i) t2.extd(cc[i]-'a',i);
    	t2.inii();
    	s1[0].insert((node){0});
    	zr=s1[0].begin();
    	dfs(1);
    	printf("%d
    ",ans);
    	return 0; 
    }
    
  • 相关阅读:
    奥巴马邻居卖房的启示,彻底改变你的思维!
    CentOS7.0安装Nginx 1.7.4
    CentOS 7 下安装 Nginx
    C# 关于线程锁lock的使用方法
    内存屏障、编译屏障:
    linux环境下安装nginx步骤
    一、为什么要学习Java虚拟机?
    Linux CentOS系统上安装Eclipse
    poj 3311 Hie with the Pie (TSP问题)
    怎样初始化一个指针数组
  • 原文地址:https://www.cnblogs.com/smyjr/p/11524303.html
Copyright © 2020-2023  润新知