启发式合并&Manacher


启发式合并&Manacher


启发式合并

概念:每一次合并利用贪心的思想把小的部分合并到大的部分之中,因为每一次合并后的区间大小一定会变为原来空间的两倍以上,所以时间复杂度为O(nlogn)。

2154. 梦幻布丁 - AcWing题库

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e5+10,M = 1e6+10;
int n,m,ans;
int head[M],idx;
struct Edge{
    int next,to;
}edge[N];
int color[N],sz[M],p[M];
void add(int a,int b)
{
    edge[idx]={head[a],b},head[a]=idx++;
    sz[a]++;
}
void merge(int &x,int &y)
{
    if(x==y)    return;
    if(sz[x]>sz[y]) swap(x,y);
    for(int i=head[x];~i;i=edge[i].next)
    {
        int j=edge[i].to;
        ans-=(color[j-1]==y)+(color[j+1]==y);
    }
    for(int i=head[x];~i;i=edge[i].next)
    {
        int j=edge[i].to;
        color[j]=y;
        if(edge[i].next==-1)
        {
            edge[i].next=head[y],head[y]=head[x];
            break;
        }
    }
    head[x]=-1;
    sz[y]+=sz[x],sz[x]=0;
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof head);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&color[i]);
        if(color[i]!=color[i-1])    ans++;
        add(color[i],i);
    }
    for(int i=0;i<M;i++)   p[i]=i;
    while(m--)
    {
        int op;
        scanf("%d",&op);
        if(op==2)   printf("%d\n",ans);
        else{
            int x,y;
            scanf("%d%d",&x,&y);
            merge(p[x],p[y]);
        }
    }
    return 0;
}

manacher

manacher算法解决的一般是回文串的问题,回文串长度必须是奇数,所以我们需要做一个初始化使他为奇数,我们从左向右遍历维护当前最长的回文串,设最长的回文串的中点为mid,右端点为mr,因此在遍历的时候,如果i<mr那么他的p[i]起点一定为min(p[2*mid-i],mr-i),因为对称性,因为此算法的右端点一直是向右单调移动,所以时间复杂度为o(n)。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 3e7+10;
char a[N],b[N];
int n,p[N],len;
void init()
{
	n=strlen(a);
	b[len++]='^',b[len++]='#';
	for(int i=0;i<n;i++)	b[len++]=a[i],b[len++]='#';
	b[len++]='$';
}
void manacher()
{
	int mid,mr=0;
	for(int i=1;i<len;i++)
	{
		if(i<mr)	p[i]=min(p[2*mid-i],mr-i);
		else	p[i]=1;
		while(b[i-p[i]]==b[i+p[i]])	p[i]++;
		if(i+p[i]>mr)	mr=p[i]+i,mid=i;
	}
}
int main()
{
	scanf("%s",a);
	init();
	manacher();
	int res=0;
	for(int i=1;i<len;i++)	res=max(res,p[i]);
	printf("%d\n",res-1);
	return 0;
}


文章作者: Dydong
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Dydong !
  目录