FJWC2020 Day3 题解

T1

Description

给你一棵 \(n\) 个点的树和 \(q\) 个询问。每次询问给出 \(a,d_a,b,d_b\),要你找到任意一个满足 \(dist(a,u)=d_a\)\(dist(b,u)=d_b\) 的点 \(u\)。找不到输出 \(-1\)

\(1\leq n,q\leq 10^6\)。时空限制 \(5s/512MB\)

Solution

要先实现一个函数 \(calc(x,y,d)\) 找到路径 \(x→y\) 上到 \(x\) 的距离为 \(d\) 的点。找不到返回 \(-1\)。令 \(z=lca(x,y)\),若 \(d\leq dist(x,z)\),则 \(ans=jump(x,d)\),否则 \(ans=jump(y,dist(x,y)-d)\)。其中 \(jump(x,d)\) 表示 \(x\)\(d\) 级祖先,可以用倍增实现。

接下来,设 \(c=lca(a,b)\),分 \(4\) 种情况讨论。

  1. \(u\)\(a\) 子树中。要满足 \(d_a+dist(a,b)=d_b\)。找到 \(u\) 子树中最深的节点 \(v\)\(ans=calc(u,v,d_a)\)
  2. \(u\)\(b\) 子树中,同理。
  3. \(u\) 在路径 \(a→b\) 上某个点 \(y\) 的子树里,\(y≠a,y≠b\)。此时要满足 \(d_a+d_b\geq dist(a,b)\),然后有: \(dist(a,y)+dist(b,y)=dist(a,b),d_a-d_b=dist(a,y)-dist(b,y)\)。可以解出 \(dist(a,y)\) 从而找到 \(y\),注意如果解出的 \(dist(a,y)\) 不是整数,无解。接下来,若 \(y≠c\),设 \(y\)\(a→b\) 路径上的子节点为 \(x\)。找到子树 \(y\) 中除了子树 \(x\) 以外的最深点 \(t\)\(ans=calc(y,t,d_a-dist(a,y))\)。若 \(y=c\)\(y\)\(a→b\) 路径上的子节点有两个,同样处理即可。记 \(Max(u)\)\(u\) 这个子树中最深的点的深度,那么需要预处理出每个点 \(Max\) 最大的 \(3\) 个子节点,以及每个点的子树中最深的点是哪个。
  4. \(u\) 在子树 \(c\) 外,需要满足 \(d_a-d_b=dist(a,c)-dist(b,c),d_a+d_b\geq dist(a,b)\)。设子树 \(c\) 外离 \(c\) 最远的点是 \(g_c\),那么 \(ans=calc(c,g_c,d_a-dist(a,c))\)\(g\) 用换根 \(\text{dp}\) 预处理即可。

时间复杂度 \(O(n\log n)\)

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

template <class t>
inline void read(t & res)
{
	char ch;
	while (ch = getchar(), !isdigit(ch));
	res = ch ^ 48;
	while (ch = getchar(), isdigit(ch))
	res = res * 10 + (ch ^ 48);
}

template <class t>
inline void print(t x)
{
	if (x < 0)
	{
		putchar('-');
		x = ~x + 1;
	}
	if (x > 9) print(x / 10);
	putchar(x % 10 + 48);
}

const int e = 1e6 + 5, o = e << 1;

int a[e], b[e], dep[e], n, q, num, nxt[o], go[o], adj[e], c[e], d[e], pos[o], cnt, 
	logn[o], st[o][21], g[e];
int dfn[e], f[e][20], ans, s3[e], t3[e];

inline void add(int x, int y)
{
	nxt[++num] = adj[x]; adj[x] = num; go[num] = y;
	nxt[++num] = adj[y]; adj[y] = num; go[num] = x;
}

inline void dfs1(int u, int pa)
{
	dfn[u] = ++cnt;
	dep[u] = dep[pa] + 1;
	pos[cnt] = u; a[u] = b[u] = c[u] = d[u] = u;
	int i;
	for (i = 0; i < 19; i++) f[u][i + 1] = f[f[u][i]][i];
	for (i = adj[u]; i; i = nxt[i])
	{
		int v = go[i];
		if (v == pa) continue;
		f[v][0] = u;
		dfs1(v, u);
		pos[++cnt] = u;
		if (dep[c[v]] > dep[c[u]])
		{
			t3[u] = d[u];
			d[u] = c[u];
			c[u] = c[v];
			
			s3[u] = b[u];
			b[u] = a[u];
			a[u] = v;
		}
		else if (dep[c[v]] > dep[d[u]])
		{
			t3[u] = d[u];
			d[u] = c[v];
			
			s3[u] = b[u];
			b[u] = v;
		}
		else if (dep[c[v]] > dep[t3[u]])
		{
			t3[u] = c[v];
			s3[u] = v;
		}
	}
}

inline void init()
{
	int i, j;
	logn[0] = -1;
	for (i = 1; i <= cnt; i++)
	{
		logn[i] = logn[i >> 1] + 1;
		st[i][0] = pos[i];
	}
	for (j = 1; (1 << j) <= cnt; j++)
	for (i = 1; i + (1 << j) - 1 <= cnt; i++)
	{
		int u = st[i][j - 1], v = st[i + (1 << j - 1)][j - 1];
		if (dep[u] < dep[v]) st[i][j] = u;
		else st[i][j] = v;
	}
}

inline int lca(int l, int r)
{
	l = dfn[l]; r = dfn[r];
	if (l > r) swap(l, r);
	int k = logn[r - l + 1], u = st[l][k], v = st[r - (1 << k) + 1][k];
	return dep[u] < dep[v] ? u : v;
}

inline int dist(int x, int y)
{
	int z = lca(x, y);
	return dep[x] + dep[y] - (dep[z] << 1);
}

inline int jump(int x, int d)
{
	for (int i = 19; i >= 0; i--)
	if (d & (1 << i)) x = f[x][i];
	return x;
}

inline int calc(int x, int y, int d)
{
	int z = lca(x, y), dis = dep[x] + dep[y] - (dep[z] << 1);
	if (d <= dep[x] - dep[z]) return jump(x, d);
	else return jump(y, dis - d);
}

inline void dfs2(int u, int pa)
{
	int i;
	for (i = adj[u]; i; i = nxt[i])
	{
		int v = go[i];
		if (v == pa) continue;
		g[v] = g[u];
		if (a[u] == v)
		{
			if (dist(d[u], v) > dist(g[v], v)) g[v] = d[u];
		}
		else
		{
			if (dist(c[u], v) > dist(g[v], v)) g[v] = c[u];
		}
		dfs2(v, u);
	}
}

inline int solve12(int u, int v, int du, int dv, int z)
{
	int dis = dep[u] + dep[v] - (dep[z] << 1);
	if (dv == du + dis)
	{
		if (z == u)
		{
			int fv = calc(u, v, 1);
			if (fv != a[u])
			{
				if (dep[c[u]] - dep[u] >= du) return calc(u, c[u], du);
			}
			else if (dep[d[u]] - dep[u] >= du) return calc(u, d[u], du);
		}
		else if (dep[c[u]] - dep[u] >= du) return calc(u, c[u], du);
	}
	if (du == dv + dis)
	{
		if (z == v)
		{
			int fu = calc(v, u, 1);
			if (fu != a[v])
			{
				if (dep[c[v]] - dep[v] >= dv) return calc(v, c[v], dv);
			}
			else if (dep[d[v]] - dep[v] >= dv) return calc(v, d[v], dv);
		}
		else if (dep[c[v]] - dep[v] >= dv) return calc(v, c[v], dv);
	}
	return -1;
}

inline int solve3(int u, int v, int du, int dv, int z) 
{
	int dis = dep[u] + dep[v] - (dep[z] << 1);
	if (du + dv >= dis)
	{
		int del = du - dv;
		if ((dis + del) & 1) return -1;
		int a1 = dis + del >> 1, b1 = dis - a1, y = calc(u, v, a1), tot = du - a1;
		if (a1 < 0 || b1 < 0) return -1;
		if (y == u || y == v) return -1;
		if (y == z)
		{
			int fu = jump(u, dep[u] - dep[z] - 1), fv = jump(v, dep[v] - dep[z] - 1);
			if (a[z] != fu && a[z] != fv)
			{
				if (dep[c[z]] - dep[z] >= tot) return calc(z, c[z], tot);
			}
			else if (b[z] != fu && b[z] != fv)
			{
				if (dep[d[z]] - dep[z] >= tot) return calc(z, d[z], tot);
			}
			else
			{
				if (dep[t3[z]] - dep[z] >= tot) return calc(z, t3[z], tot);
			}
		}
		else if (a1 <= dep[u] - dep[z])
		{
			int ys = calc(u, v, a1 - 1);
			if (ys == a[y])
			{
				if (dep[d[y]] - dep[y] >= tot) return calc(y, d[y], tot);
			}
			else
			{
				if (dep[c[y]] - dep[y] >= tot) return calc(y, c[y], tot);
			}
		}
		else
		{
			int ys = calc(u, v, a1 + 1);
			if (ys == a[y])
			{
				if (dep[d[y]] - dep[y] >= tot) return calc(y, d[y], tot);
			}
			else
			{
				if (dep[c[y]] - dep[y] >= tot) return calc(y, c[y], tot);
			}
		}
	}
	return -1;
}

inline int solve4(int u, int v, int du, int dv, int z)
{
	int dis = dep[u] + dep[v] - (dep[z] << 1);
	if (du - dv == dep[u] - dep[v] && dep[u] - dep[z] <= du && dep[v] - dep[z] <= dv)
	{
		int dc = du - (dep[u] - dep[z]);
		if (dist(z, g[z]) >= dc) return calc(z, g[z], dc);
	}
	return -1;
}

int main()
{
	freopen("hunting.in", "r", stdin);
	freopen("hunting.out", "w", stdout);
	read(n); read(q);
	int u, v, i, du, dv;
	for (i = 1; i < n; i++) read(u), read(v), add(u, v);
	dfs1(1, 0);
	init();
	g[1] = 1;
	dfs2(1, 0);
	while (q--)
	{
		read(u); read(du); read(v); read(dv);
		if (u == v && du != dv)
		{
			puts("-1");
			continue;
		}
		ans = -1;
		if (u == v)
		{
			if (dist(u, g[u]) >= du) ans = calc(u, g[u], du);
			else if (dist(u, c[u]) >= du) ans = calc(u, c[u], du);
			print(ans); putchar('\n');
			continue;
		}
		int z = lca(u, v);
		ans = solve12(u, v, du, dv, z);
		if (ans == -1) ans = solve3(u, v, du, dv, z);
		if (ans == -1) ans = solve4(u, v, du, dv, z);
		print(ans); putchar('\n');
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

T2

Description

给定一张 \(n\) 个点 \(m\) 条边的无向图,求有多少个非空点集的导出子图连通。

导出子图:仅保留这个点集中的点和端点都在这个点集中的边。

无向图的边 \((x,y)\) 都满足 \(|x-y|\leq 12\)

答案对 \(2\) 取模,\(1\leq n\leq 50\),时空限制 \(2s/512MB\)

Solution

导出子图连通也就是导出子图的连通块个数 \(=1\),否则连通块个数 \(>1\)

发现在 \(mod\ 4\) 意义下,\(2^1=2,2^k=0(k>1)\)

那么考虑求所有非空点集的导出子图的 \(2^{连通块个数}\) 之和。

这个问题相当于对每个导出子图的每个点黑白染色,要求连通的点必须同色的方案数之和。

那么记 \(f[i][s]\) 表示目前做到第 \(i\) 个点,\(s\) 是一个 \(12\) 位的 \(3\) 进制数,表示 \(i-11\sim i\)\(12\) 个点的状态(不在导出子图中,染成白色,染成黑色)。转移直接枚举 \(f[i-1][s]\)\(i\) 的状态即可。

最后答案如果是 \(2\), 输出 \(1\),否则输出 \(0\)

时间复杂度 \(O(3^{12}n)\)

有个神仙用连通性 \(\text{dp}\) + 神仙剪枝,过了。

Code

#include <bits/stdc++.h>

using namespace std;

template <class t>
inline void read(t & res)
{
	char ch;
	while (ch = getchar(), !isdigit(ch));
	res = ch ^ 48;
	while (ch = getchar(), isdigit(ch))
	res = res * 10 + (ch ^ 48);
}

const int o = 531446;

int p[55], f[55][o], n, m, ans;
bool bo[55][55];

inline void add(int &x, int y)
{
	x += y; x &= 3;
}

inline int calc(int x, int y)
{
	return x / p[y] % 3;
}

int main()
{
	freopen("graph.in", "r", stdin);
	freopen("graph.out", "w", stdout);
	read(n); read(m);
	int i, s, x, y, j;
	while (m--)
	{
		read(x); read(y);
		bo[x][y] = bo[y][x] = 1;
	}
	p[0] = 1;
	for (i = 1; i <= 12; i++) p[i] = p[i - 1] * 3;
	f[1][0] = f[1][p[11]] = f[1][2 * p[11]] = 1;
	for (i = 2; i <= n; i++)
	for (s = 0; s < p[12]; s++)
	if (f[i - 1][s])
	{
		int v = f[i - 1][s], t = s / 3;
		add(f[i][t], v);
		bool pd1 = 1, pd2 = 1;
		for (j = 0; j <= 11; j++)
		if (i - 12 + j >= 1 && bo[i][i - 12 + j])
		{
			int x = calc(s, j);
			if (x == 1) pd2 = 0;
			else if (x == 2) pd1 = 0;
		}
		if (pd1) add(f[i][t + p[11]], v);
		if (pd2) add(f[i][t + 2 * p[11]], v);
	}
	for (s = 0; s < p[12]; s++) add(ans, f[n][s]);
	(ans += 3) &= 3;
	if (ans == 2) ans = 1;
	cout << ans << endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

T3

Description

定义两个字符串是相似的,当且仅当至多存在一个 \(i\) ,使得这两个字符串中只有第 \(i\) 个字母不同。

你取出了这个字符串中所有长度为 \(m\) 的子串。你想知道,对于每个长度为 \(m\) 的子串,有多少个其它长度为 \(m\) 的子串与它相似。

\(n,m\leq 10^5\),时空限制 \(3s/512MB\)

Solution

记这个串为 \(S\)\(lcp(i,j)\) 表示 \(S[i\dots n]\)\(S[j\dots n]\) 的最长公共前缀长度,\(lcs(i,j)\) 表示 \(S[1\dots i]\)\(S[1\dots j]\) 的最长公共后缀长度。

问题转化为求有多少对 \(i,j\) 满足 \(lcp(i,j)+lcs(i+m-1,j+m-1)\geq m-1\)

先对 \(S\) 的正串和反串都建 \(SAM\) 以及 \(parent\) 树。记 \(p1[i]\) 为第一棵 \(parent\) 树上 \(S[1\dots i+m-1]\) 对应点的编号,\(p2[i]\) 为第二棵 \(parent\) 树上 \(S[i\dots n]\) 对应点的编号。式子转化为 \(dep1[lca1(p1[i],p1[j])]+dep2[lca2(p2[i],p2[j])]\geq m-1\)

接下来的这个实现方法可能过于麻烦,因为菜鸡看不懂标程只好自己瞎扯了。

考虑启发式合并,维护两棵树状数组 \(c,d\),下标是第二棵树的 \(dfs\) 序。

枚举 \(lca1(p1[i],p1[j])=x\),先考虑轻子树(包括点 \(x\))之间的贡献:我们先正序枚举轻儿子 \(v\)(包括点 \(x\)),然后把子树 \(v\) \(\text{dfs}\) 一遍。设 \(\text{dfs}\) 到节点 \(u\),如果 \(u\) 对应 \(S[1\dots i+m-1]\)。记 \(y\)\(p2[i]\) 到根的路径上,满足 \(dep2[y]>=m-1-dep1[x]\) 的最深节点(用倍增找)。然后在 \(c\) 上求出有多少个点在 \(y\) 子树中,就是对 \(ans[i]\) 的贡献。

然后再把 \(v\) 子树 \(\text{dfs}\) 一遍。在 \(c\) 上把 \(dfn2[u]\) 这个位置的值 \(+1\)

然后把轻子树都 \(\text{dfs}\) 一遍,清空 \(c\) 数组。然后倒序枚举轻儿子,再执行一遍上述过程,就把轻子树(包括点 \(x\))之间的贡献全部计算好了。

考虑重子树对轻子树的贡献,维护 \(d\) 数组,位置 \(i\) 表示重子树中有几个 \(dfn2=i\) 的点。把所有轻子树的点遍历一遍,在 \(d\) 数组上区间查,即可得到重子树对其贡献。

考虑轻子树对重子树的贡献。显然不可以把重子树 \(\text{dfs}\) 一遍。记 \(x\) 的重儿子为 \(son_x\)。枚举所有轻子树中的点 \(u\),显然会对满足 \(dfn1∈[dfn1[son_x],dfn1[son_x]+sze1[son_x]-1],dfn2∈[dfn2[y],dfn2[y]+sze2[y]-1]\) 的点产生 \(1\) 的贡献。这一部分的贡献相当于矩形加,单点查,离线 \(+\) 扫描线解决即可。

这到底要遍历多少次轻子树啊。

时间复杂度 \(O(n\log ^2n)\)。常数大的一批,但是 \(3s\) 还是稳的。

Code

#include <bits/stdc++.h>

using namespace std;

template <class t>
inline void print(t x)
{
	if (x > 9) print(x / 10);
	putchar(x % 10 + 48);
}

const int e = 2e5 + 15;

struct line
{
	int l, r, v;
	
	line(){}
	line(int _l, int _r, int _v) :
		l(_l), r(_r), v(_v) {} 
};
int c[e], d[e], son[e], n, m, ans[e], p1[e], p2[e], L, f[e][18], szeA[e], szeB[e], rt;
int lst_y[e], dfn_l, dfn_r, dfnA[e], dfnB[e], timA, timB, real_ans[e];
char s[e];
vector<line>g[e];
vector<int>h[e];

struct SAM
{
	struct point
	{
		int go[26];
	}t[e];
	int maxl[e], fa[e], tot = 1, lst = 1, id[e], anc[e][18], dep[e];
	vector<int>g[e];
	
	inline void insert(char s)
	{
		int c = s - 'a', i = lst;
		lst = ++tot;
		maxl[lst] = maxl[i] + 1;
		for (; i && !t[i].go[c]; i = fa[i]) t[i].go[c] = lst;
		if (!i) fa[lst] = 1;
		else
		{
			int j = t[i].go[c];
			if (maxl[j] == maxl[i] + 1) fa[lst] = j;
			else
			{
				int p;
				t[p = ++tot] = t[j];
				fa[p] = fa[j];
				fa[j] = fa[lst] = p;
				maxl[p] = maxl[i] + 1;
				for (; i && t[i].go[c] == j; i = fa[i]) t[i].go[c] = p;
			}
		} 
	}
	
	inline void build()
	{
		for (int i = 2; i <= tot; i++) g[fa[i]].push_back(i);
	}
}A, B;

inline void change(int *c, int x, int v)
{
	for (int i = x; i <= L; i += i & -i) c[i] += v;
}

inline int query(int *c, int x)
{
	int res = 0;
	for (int i = x; i; i -= i & -i) res += c[i];
	return res;
}

inline void dfsA(int u)
{
	dfnA[u] = ++timA;
	szeA[u] = 1;
	int len = A.g[u].size(), i;
	for (i = 0; i < len; i++)
	{
		int v = A.g[u][i];
		dfsA(v);
		szeA[u] += szeA[v];
		if (szeA[v] > szeA[son[u]]) son[u] = v;
	}
}

inline void dfsB(int u)
{
	dfnB[u] = ++timB;
	szeB[u] = 1;
	int len = B.g[u].size(), i;
	for (i = 0; i < 17; i++) f[u][i + 1] = f[f[u][i]][i];
	for (i = 0; i < len; i++)
	{
		int v = B.g[u][i];
		f[v][0] = u;
		dfsB(v);
		szeB[u] += szeB[v];
	}
}

inline int jumpB(int x, int d)
{
	for (int i = 17; i >= 0; i--)
	if (f[x][i] && B.maxl[f[x][i]] >= d) x = f[x][i];
	return x;
}

inline void add(int u)
{
	if (!A.id[u]) return;
	int pos = A.id[u], z = p2[pos];
	change(c, dfnB[z], 1);
}

inline void del(int u)
{
	if (!A.id[u]) return;
	int pos = A.id[u], z = p2[pos];
	change(c, dfnB[z], -1);
}

inline void ask(int u, int x)
{
	if (!A.id[u]) return;
	int pos = A.id[u], z = p2[pos], y = jumpB(z, m - 1 - A.maxl[x]);
	lst_y[u] = y;
	ans[pos] += query(c, dfnB[y] + szeB[y] - 1) - query(c, dfnB[y] - 1);
}

inline void calc_son(int u)
{
	if (!A.id[u]) return;
	int pos = A.id[u], z = p2[pos], y = lst_y[u];
	ans[pos] += query(d, dfnB[y] + szeB[y] - 1) - query(d, dfnB[y] - 1);
}

inline void ins(int u)
{
	if (!A.id[u]) return;
	int pos = A.id[u], z = p2[pos];
	change(d, dfnB[z], 1);
}

inline void clear(int u)
{
	if (!A.id[u]) return;
	int pos = A.id[u], z = p2[pos];
	change(d, dfnB[z], -1);
}

inline void join(int u)
{
	if (!A.id[u]) return;
	int y = lst_y[u];
	g[dfn_l].push_back(line(dfnB[y], dfnB[y] + szeB[y] - 1, 1));
	g[dfn_r + 1].push_back(line(dfnB[y], dfnB[y] + szeB[y] - 1, -1));
}

inline void dfs_add(int u)
{
	add(u);
	int len = A.g[u].size(), i;
	for (i = 0; i < len; i++) dfs_add(A.g[u][i]);
}

inline void dfs_del(int u)
{
	del(u);
	int len = A.g[u].size(), i;
	for (i = 0; i < len; i++) dfs_del(A.g[u][i]);
}

inline void dfs_ask(int u, int x)
{
	ask(u, x);
	int len = A.g[u].size(), i;
	for (i = 0; i < len; i++) dfs_ask(A.g[u][i], x); 
}

inline void dfs_cs(int u)
{
	calc_son(u);
	int len = A.g[u].size(), i;
	for (i = 0; i < len; i++) dfs_cs(A.g[u][i]); 
}

inline void dfs_ins(int u)
{
	ins(u);
	int len = A.g[u].size(), i;
	for (i = 0; i < len; i++) dfs_ins(A.g[u][i]);
}

inline void dfs_clear(int u)
{
	clear(u);
	int len = A.g[u].size(), i;
	for (i = 0; i < len; i++) dfs_clear(A.g[u][i]);
}

inline void dfs_join(int u)
{
	join(u);
	int len = A.g[u].size(), i;
	for (i = 0; i < len; i++) dfs_join(A.g[u][i]);
}

inline void dfsC(int u, bool op)
{
	int i, len = A.g[u].size();
	for (i = 0; i < len; i++)
	{
		int v = A.g[u][i];
		if (v != son[u]) dfsC(v, 0);
	}
	if (son[u]) dfsC(son[u], 1);
	
	ask(u, u); add(u);
	for (i = 0; i < len; i++)
	{
		int v = A.g[u][i];
		if (v != son[u])
		{
			dfs_ask(v, u);
			dfs_add(v);
		}
	}
	del(u);
	for (i = 0; i < len; i++)
	{
		int v = A.g[u][i];
		if (v != son[u]) dfs_del(v);
	}
	
	for (i = len - 1; i >= 0; i--)
	{
		int v = A.g[u][i];
		if (v != son[u])
		{
			dfs_ask(v, u);
			dfs_add(v);
		}
	}
	ask(u, u);
	for (i = 0; i < len; i++)
	{
		int v = A.g[u][i];
		if (v != son[u]) dfs_del(v);
	}
	
	calc_son(u);
	for (i = 0; i < len; i++)
	{
		int v = A.g[u][i];
		if (v != son[u]) dfs_cs(v);
	}
	
	if (op)
	{
		ins(u);
		for (i = 0; i < len; i++)
		{
			int v = A.g[u][i];
			if (v != son[u]) dfs_ins(v);
		}
	}
	else if (son[u]) dfs_clear(son[u]);
	
	if (son[u])
	{
		dfn_l = dfnA[son[u]]; 
		dfn_r = dfn_l + szeA[son[u]] - 1;
		join(u);
		for (i = 0; i < len; i++)
		{
			int v = A.g[u][i];
			if (v != son[u]) dfs_join(v);
		}
	}
}

int main()
{
	freopen("string.in", "r", stdin);
	freopen("string.out", "w", stdout);
	cin >> n >> m;
	int i, j;
	scanf("%s", s + 1);
	for (i = 1; i <= n; i++)
	{
		A.insert(s[i]);
		if (i >= m) A.id[A.lst] = i - m + 1, p1[i - m + 1] = A.lst;
	}
	for (i = n; i >= 1; i--)
	{
		B.insert(s[i]);
		if (i + m - 1 <= n) B.id[B.lst] = i, p2[i] = B.lst;
	}
	A.build(); B.build(); L = B.tot;
	dfsA(1); dfsB(1); dfsC(1, 0);
	memset(c, 0, sizeof(c));
	for (i = 1; i <= n - m + 1; i++) h[dfnA[p1[i]]].push_back(i);
	for (i = 1; i <= A.tot; i++)
	{
		int leng = g[i].size();
		for (j = 0; j < leng; j++)
		{
			line tmp = g[i][j];
			change(c, tmp.l, tmp.v);
			change(c, tmp.r + 1, -tmp.v);
		}
		int lenh = h[i].size();
		for (j = 0; j < lenh; j++)
		{
			int x = h[i][j];
			ans[x] += query(c, dfnB[p2[x]]);
		}
	}
	for (i = 1; i <= n - m + 1; i++)
	{
		print(ans[i]);
		if (i == n - m + 1) putchar('\n');
		else putchar(' ');
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

posted @ 2020-01-25 15:12  花淇淋  阅读(709)  评论(1编辑  收藏  举报