[雅礼集训 2017 Day7] 事情的相似度

一、题目

点此看题

二、题目

后缀自动机乱杀。

他问的是前缀之间的最长后缀,我们对正串建出后缀自动机,然后把前缀在自动机上面打上标记。根据后缀自动机的性质,最长后缀就是两个前缀在 \(\tt parent \;tree\)\(\tt lca\)\(len\)

对于一个前缀对 \((l,r)\) ,那么他可以对 \(L\leq l,r\leq R\) 的询问 \((L,R)\) 产生贡献。因为是 \(\tt lca\) ,所以可以想到通过树上启发式合并找出这些前缀对,那么我们在合并子树的时候就要考虑子树之间新产生的点对。

貌似这样前缀对的数量是 \(O(n^2)\) 的,合并的时候我们只需要找最接近的前缀,因为贡献都是一样的,但是找最接近的能贡献到的是最多的,所以数量是 \(O(n\log n)\),用 \(\tt set\) 维护启发式合并。

那么时间复杂度 \(O(n\log^2 n)\),最后算贡献的时候本质上是一个二维偏序,所以直接排序就行了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int M = 200005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k,tot,cnt,last,bit[M],f[M],ans[M];char t[M];
set<int> s[M];
struct edge
{
	int v,next;
	edge(int V=0,int N=0) : v(V) , next(N) {}
}e[2*M];
struct node
{
	int fa,ch[2],len;
}a[M];
struct zxy
{
	int l,r,x;
	bool operator < (const zxy &b) const
	{
		return r<b.r;
	}
}q[M],p[20*M];
void add(int c)
{
    int p=last,np=last=++cnt;
    a[np].len=a[p].len+1;
    for(;p && !a[p].ch[c];p=a[p].fa) a[p].ch[c]=np;
    if(!p) a[np].fa=1;
    else
    {
        int q=a[p].ch[c];
        if(a[q].len==a[p].len+1) a[np].fa=q;
        else
        {
            int nq=++cnt;
            a[nq]=a[q];a[nq].len=a[p].len+1;
            a[q].fa=a[np].fa=nq;
            for(;p && a[p].ch[c]==q;p=a[p].fa) a[p].ch[c]=nq;
        }
    }
}
void dfs(int u,int fa)
{
	for(int i=f[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(v==fa) continue;
		dfs(v,u);
		if(s[u].size()<s[v].size()) swap(s[u],s[v]);
		set<int>::iterator it,pre,nxt;
		for(it=s[v].begin();it!=s[v].end();it++)
		{
			s[u].insert(*it);
			pre=nxt=s[u].find(*it);nxt++;
			if(pre!=s[u].begin()) pre--,p[++k]=zxy{*pre,*it,a[u].len};
			if(nxt!=s[u].end()) p[++k]=zxy{*it,*nxt,a[u].len};
			s[u].erase(*it); 
		}
		for(it=s[v].begin();it!=s[v].end();it++)
			s[u].insert(*it);
	}
}
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int y)
{
	for(int i=x;i>=1;i-=lowbit(i))
		bit[i]=max(bit[i],y);
}
int ask(int x)
{
	int res=0;
	for(int i=x;i<=n;i+=lowbit(i))
		res=max(res,bit[i]);
	return res;
}
signed main()
{
	n=read();m=read();
	scanf("%s",t+1);
	cnt=last=1;
	for(int i=1;i<=n;i++)
	{
		add(t[i]-'0');
		s[last].insert(i);
	}
	for(int i=2;i<=cnt;i++)
	{
		int j=a[i].fa;
		e[++tot]=edge(i,f[j]),f[j]=tot;
		e[++tot]=edge(j,f[i]),f[i]=tot;
	}
	dfs(1,0);
	sort(p+1,p+1+k);
	for(int i=1;i<=m;i++)
	{
		int l=read(),r=read();
		q[i]=zxy{l,r,i};
	}
	sort(q+1,q+1+m);
	for(int i=1,j=1;i<=m;i++)
	{
		while(j<=k && p[j].r<=q[i].r) add(p[j].l,p[j].x),j++;
		ans[q[i].x]=ask(q[i].l);
	}
	for(int i=1;i<=m;i++)
		printf("%d\n",ans[i]);
}
posted @ 2020-12-19 19:55  C202044zxy  阅读(201)  评论(0编辑  收藏  举报