BZOJ 3238 AHOI 2013 差异 后缀树

题目大意:求所有后缀长度减去LCP长度的二倍。

思路:之前用后缀数组写过,但是做法并不是很直观。现在学了后缀树再来写一次,这次思路就很清晰了。

首先我们把字符串按照倒序插入到后缀树中。形成的后缀树有一个很好的性质,连个后缀节点的LCA就是这两个后缀的LCP的位置,LCA的len值自然就是两个后缀的LCP。

建好树之后,进行一次树形DP,统计出来每两个后缀的LCP长度,计入总答案。

这东西以后不用指针写了,简直DT死了。。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 1000010
using namespace std;

struct Complex{
	Complex *tranc[26],*father;
	int len,id,size;
}none,*nil = &none,*root,*last;
Complex mempool[MAX],*C = mempool;
Complex *NewComplex(int _,bool is_suffix)
{
	static int cnt = 0;
	C->id = ++cnt;
	C->size = is_suffix;
	fill(C->tranc,C->tranc + 26,nil);
	C->father = nil;
	C->len = _;
	return C++;
}

void Pretreatment()
{
	root = last = NewComplex(0,false);
}

char s[MAX];

inline void Add(int c)
{
	Complex *np = NewComplex(last->len + 1,true),*p = last;
	for(; p != nil && p->tranc[c] == nil; p = p->father)	p->tranc[c] = np;
	if(p == nil)	np->father = root;
	else {
		Complex *q = p->tranc[c];
		if(q->len == p->len + 1)	np->father = q;
		else {
			Complex *nq = NewComplex(p->len + 1,false);
			nq->father = q->father;
			q->father = np->father = nq;
			memcpy(nq->tranc,q->tranc,sizeof(q->tranc));
			for(; p != nil && p->tranc[c] == q; p = p->father)	p->tranc[c] = nq;
		}
	}
	last = np;
}

int head[MAX],total;
int next[MAX],aim[MAX];

void Add(int x,int y)
{
	next[++total] = head[x];
	aim[total] = y;
	head[x] = total;
}

long long sum = 0;

void DFS(int x,int last)
{
	for(int i = head[x]; i; i = next[i]) {
		DFS(aim[i],x);
		mempool[x].size += mempool[aim[i]].size;
	}
	mempool[x].len -= mempool[last].len;
	sum += (long long)mempool[x].size * (mempool[x].size - 1) * mempool[x].len;
}

int main()
{
	Pretreatment();
	scanf("%s",s);
	int length = strlen(s);
	for(int i = length - 1; ~i; --i)
		Add(s[i] - 'a');
	for(Complex *p = mempool + 1; p != C; ++p)
		Add(p->father->id - 1,p->id - 1);
	for(int i = head[0]; i; i = next[i])	DFS(aim[i],0);
	cout << (long long)(length + 1) * length * (length - 1) / 2 - sum << endl;
	return 0;
}
时间: 2024-10-26 04:55:44

BZOJ 3238 AHOI 2013 差异 后缀树的相关文章

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

[BZOJ 3238] [AHOI 2013] 差异

题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么我们可以用这个 Height 数组求出所有后缀之间 LCP 的和. 我们用 f[i] 表示字典序第 i 的后缀与字典序在 i 之后的所有后缀的 LCP 的和. 我们知道,两个后缀的 LCP 为 Height 数组中这两个后缀之间的最小值. 我们从最后向前推 i ,用一个单调栈维护后面的 Height

【BZOJ 3238】 [Ahoi2013]差异

3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 777 Solved: 359 [Submit][Status][Discuss] Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Output 54 HINT 2<=N<=500000,S由小写英文字母组成 后缀数组+单调队列. 式子中前两项的和可以直接求出为

[AHOI 2013] 差异

[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=3238 [算法] 首先 , LCP(Ti , Tj) = min{ height[rank[Ti] + 1] , height[rank[Ti] + 2] , ... , height[rank[Tj]] }          显然 , 我们只要计算后缀两两之间的LCP之和即可 对于一个右端点R , 随着L的减小 , min{height[L] , height[L + 1] ..

BZOJ 3236 AHOI 2013 作业 莫队算法

题目大意:给出一些数,问在一个区间中不同的数值有多少种,和在一个区间中不同的数值有多少个. 思路:由于没有修改,所以就想到了莫队算法.然后我写了5K+的曼哈顿距离最小生成树,然后果断T了.(100s的时限啊,刷status都要刷疯了..,结果最后加了手写读入也没能A).后来果断放弃,写了分块版的莫队算法.84sAC...这题卡的..貌似莫队并不是正解. 其实用分块来写莫队就很简单了.只需要将所有询问的区间排序,左端点所在块作为第一键值,右端点作为第二季键值排序,之后就可以转移了.理论上来时还是曼

BZOJ 3238 [Ahoi2013]差异(后缀自动机)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3238 [题目大意] 给出一个串,设T[i]表示从第i位开始的后缀, 求sum(len(T[i])+len(T[j])-2*lcp(T[i],T[j])) [题解] 根据反串的后缀自动机建立后缀树, 则两点的LCA在自动机中的length就是他们的LCP, 树形DP统计一下即可. [代码] #include <cstdio> #include <algorithm> #i

BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有两幅面孔呢). 看代码实现吧,不大容易口头解释,把加的和减的分开算就可以了,减去的通过倒着建sam(相当于建一棵后缀树),然后算每个len取的次数实现,注意树归中一些避免重复操作. 1 /********************************************************

BZOJ 3238 AHOI2013 差异 后缀自动机

题目大意:给定一个字符串,求Σ[1<=i<j<=n]|Ti|+|Tj|-2|LCP(Ti,Tj)| 前两项是可以O(1)求的 我们要求的就是LCP之和 对反串建立后缀自动机 那么parent指针连成的树就是后缀树 直接在后缀树上DP就行- - 对于每个节点统计所有子树两两right集合大小乘积之和乘上这个节点的深度即可 QY神在学校讲了一天的SAM... 现在我觉得我还是回去学大型建筑机械吧233- - #include <map> #include <vector&g

【BZOJ 3238】差异 后缀自动机+树形DP

题意 给定字符串,令$s_i$表示第$i$位开始的后缀,求$\sum_{1\le i < j \le n} len(s_i)+len(s_j)-2\times lcp(s_i,s_j)$ 先考虑前面的和式,直接计算为$\frac{n(n^2-1)}{2}$,考虑后面的和式,$lcp$相关可以用sam求解,sam形成的parent树是原串的前缀树,所以两个串的最长公共后缀是在parent树上最近公共祖先对应的状态的长度$maxlen_s-maxlen_{pa_s}$,将原串反向建立sam得到后缀树