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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM