[AHOI2013]差异 【SAM后缀树+树形dp】

[AHOI2013]差异

万能的后缀树啊2333

建出后缀树,一个节点的祖先节点都是他的后缀,一个节点的儿子节点都是以他为后缀的串。所以两个串的lcs就是他们的lca节点的 l e n len len

这道题可以对反串建后缀树,树边 ( u , v ) (u,v) (u,v) 权值为 ∣ l e n u − l e m v ∣ |len_u-lem_v| lenulemv ,答案就是所有关键点之间的路径权值之和。

#include<bits/stdc++.h>
#define N 1000006
using namespace std;
typedef long long ll;
char s[N];
int lst,cnt,link[N];
ll n,ans,len[N],siz[N];
vector<int> son[N];
struct SAM{
	map<char,int> trans[N];
	void insert(char c){
		int z=++cnt,p=lst; siz[z]=1,len[z]=len[lst]+1;
		while(p!=-1&&!trans[p].count(c))trans[p][c]=z,p=link[p];
		if(p==-1) link[z]=0;
		else{
			int q=trans[p][c];
			if(len[q]==len[p]+1) link[z]=q; 
			else{
				int clone=++cnt; len[clone]=len[p]+1;
				trans[clone]=trans[q];
				while(p!=-1&&trans[p][c]==q) trans[p][c]=clone,p=link[p];
				link[clone]=link[q],link[z]=link[q]=clone;
			}
		}
		lst=z;
	}
	void dp(int x=0){
		int y;
		for(int i=0;i<son[x].size();i++) y=son[x][i],dp(y),siz[x]+=siz[y];
		if(x) ans+=siz[x]*(n-siz[x])*(len[x]-len[link[x]]); 
	}
}sam;
int main(){
	scanf("%s",s+1); n=strlen(s+1);
	link[0]=-1;
	for(int i=n;i>=1;i--) sam.insert(s[i]);
	for(int i=1;i<=cnt;i++) son[link[i]].push_back(i);
	sam.dp();
	cout<<ans;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值