zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    填空练习(指向指针的指针)
    练习指针函数:编写一个函数,输入n为偶数时,调用fa函数,当输入n为奇数时,调用fb函数(利用指针函数)。
    输入一个整数,并将其反转后输出。
    有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
    案例练习
    操作don树
    Node对象
    element对象二
    element对象
    在末尾添加节点
  • 原文地址:https://www.cnblogs.com/cyf32768/p/12233066.html
Copyright © 2011-2022 走看看