5.29 省选模拟赛 波波老师 SAM 线段树 单调队列 并查集

LINK:波波老师

LINK:同bzoj 1396 识别子串

不过前者要求线性做法 后者可以log过。实际上前者也被我一个log给水过了.

其实不算很水 我自认跑的很快罢了.

都是求经过一个位置的最短的 在整个字符串中只出现过一次的子串。

SAM很容易完成这个东西.

考虑对于计算每个节点的贡献 容易发现是一个区间整体赋值和一个等差数列 不过太懒了不想维护这个等差数列 我反着建SAM维护最右左端点了。

就变成了两个区间最值问题。完全可以标记永久化 可能有点卡空间。

当然考场上也思考了O(n)的做法 先考虑等差数列那个地方 由于right集大小为1 那么显然这个点的len是一直到之后都有效所以可以直接标记最后取max

考虑区间取min操作。当时想法是排序后利用并查集 排列可以利用桶排 然后复杂度就降到\(n\cdor (a)\)

可以发现桶排序之后可以利用单调队列+链表 来实现O(n).细节有点繁琐 不再赘述.

标记永久化还是很快滴 (比其他dalao写zkw线段树要快一点.当时我也想写zkw线段树 不过不太熟练所以就没用

const int MAXN=5000010;
int n,cnt=1,last=1;
int sum[MAXN<<2],w[MAXN<<2];//一个取max 一个取min.
struct wy
{
	int ch[5];
	int fa,len;
}t[MAXN<<1];
char a[MAXN];ll ans;
int c[MAXN],vis[MAXN<<1],s[MAXN<<1];
inline void insert(int x)
{
	int p=last;
	int np=last=++cnt;
	len(np)=len(p)+1;
	while(p&&!t[p].ch[x])
	{
		t[p].ch[x]=np;
		p=f(p);
	}
	if(!p)f(np)=1;
	else
	{
		int q=t[p].ch[x];
		if(len(q)==len(p)+1)f(np)=q;
		else
		{
			int nq=++cnt;
			t[nq]=t[q];
			len(nq)=len(p)+1;
			f(np)=f(q)=nq;
			while(p&&t[p].ch[x]==q)
			{
				t[p].ch[x]=nq;
				p=f(p);
			}
		}
	}
}
inline void topsort()
{
	rep(1,cnt,i)++c[len(i)];
	rep(1,n,i)c[i]+=c[i-1];
	rep(1,cnt,i)s[c[len(i)]--]=i;
}
inline void change(int p,int l,int r,int L,int R,int x)
{
	if(l==L&&r==R)return sum[p]=min(sum[p],x),void();
	int mid=(l+r)>>1;
	if(L>mid)return change(yy,mid+1,r,L,R,x),void();
	if(R<=mid)return change(zz,l,mid,L,R,x),void();
	change(zz,l,mid,L,mid,x);change(yy,mid+1,r,mid+1,R,x);
}
inline void modify(int p,int l,int r,int L,int R,int x)
{
	if(l==L&&r==R)return w[p]=max(w[p],x),void();
	int mid=(l+r)>>1;
	if(L>mid)return modify(yy,mid+1,r,L,R,x),void();
	if(R<=mid)return modify(zz,l,mid,L,R,x),void();
	modify(zz,l,mid,L,mid,x);modify(yy,mid+1,r,mid+1,R,x);
}
inline void dfs(int p,int l,int r,int S,int W)
{
	S=min(S,sum[p]);W=max(W,w[p]);
	if(l==r)
	{
		if(W==0)W=-INF;
		ans+=min(S,l-W+1);
		return;
	}
	int mid=(l+r)>>1;
	dfs(zz,l,mid,S,W);
	dfs(yy,mid+1,r,S,W);
}
int main()
{
	freopen("bobo.in","r",stdin);
    freopen("bobo.out","w",stdout);
	gc(a);n=strlen(a+1);
	fep(n,1,i)insert(a[i]-'a'),vis[last]=i;
	topsort();
	memset(sum,0x3f,sizeof(sum));
	fep(cnt,2,i)
	{
		int x=s[i];
		//cout<<vis[x]<<' '<<len(x)<<endl;
		if(vis[x]==-1)vis[f(x)]=-1;
		else 
		{
			if(!vis[f(x)])vis[f(x)]=vis[x];
			else vis[f(x)]=-1;
		}
		if(vis[x]!=-1)
		{
			change(1,1,n,vis[x],vis[x]+len(f(x)),len(f(x))+1);
			modify(1,1,n,vis[x]+len(f(x)),vis[x]+len(x)-1,vis[x]);
		}
	}
	dfs(1,1,n,INF,0);putl(ans);
	return 0;
}
上一篇:Windows硬盘文件分析取证(新建的用户名)


下一篇:谈判技巧——签合同