BZOJ4231 回忆树

1|0BZOJ4231 回忆树

Link

1|1题目分析:

很恶心的题目呢?(可能是我太菜了

首先我们把树上的所有的询问看成两部分,一部分是经过 lca 的部分,另一部分是链的形式。很明显只有这两种贡献。

那么对于第一种来说,因为总共的字符集大小是不超过 300000 的,所以我们可以暴力找出经过 lca 的这一部分然后进行 KMP 匹配。这一部分的复杂度是 O(2|S|) 的。

那么对于第二种来说,我们可以看成是一种差分,即从根到点的差分。我们可以对于询问串建一个 AC 自动机,这样的话我们就可以在 dfs 的时候进行统计答案,遍历到当前的节点加上贡献,出去的时候减去贡献,因为是子树内权值和。所以考虑离线 + 树状数组实现。

SB 错误:出去的时候减错点了,导致最后出现了负数(大雾

1|2Code:

//editor : DRYAYST //Wo shi ge da SHA BI #include<bits/stdc++.h> #define g() getchar() #define il inline #define ull unsigned long long #define eps 1e-10 #define ll long long #define pa pair<int, int> #define for_1(i, n) for(int i = 1; i <= (n); ++i) #define for_0(i, n) for(int i = 0; i < (n); ++i) #define for_xy(i, x, y) for(int i = (x); i <= (y); ++i) #define for_yx(i, y, x) for(int i = (y); i >= (x); --i) #define for_edge(i, x) for(int i = head[x]; i; i = nxt[i]) //#define int long long #define DB double #define ls (p<<1) #define rs (p<<1|1) #define m_p make_pair #define fi first #define se second using namespace std; const int N = 2e5 + 10, INF = 0x7f7f7f7f, mod = 1e9 + 7; inline int re() { int x = 0, p = 1; char ch = getchar(); while(ch > '9' || ch < '0') {if(ch == '-') p = -1; ch = getchar();} while(ch <= '9' and ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();} return x * p; } int head[N], ver[N<<1], nxt[N<<1], tot, edge[N<<1]; il void add(int x, int y, int z) {ver[++tot] = y; nxt[tot] = head[x]; head[x] = tot; edge[tot] = z; } int n, m, cnt, num, fk; int f[N][18], fval[N], dep[N], tr[N<<1][30], pos[N][2], st[N<<1], ed[N<<1], fail[N<<1], sum[N], net[N], ans[N]; char St[N], s1[N*2]; vector<pa> Ps[N]; vector<int> e[N<<1], ID[N]; il int lowbit(int x) {return x & (-x); } il void Add(int x, int k) {while(x <= fk) sum[x] += k, x += lowbit(x);} il int Ask(int x) {int ans = 0; while(x) ans += sum[x], x -= lowbit(x); return ans; } il int Insert(int tp, char *s) { int u = 0; int len = strlen(s + 1); if(tp == -1) {for(int i = len; i >= 1; --i) {int now = s[i] - 'a' + 1; if(!tr[u][now]) tr[u][now] = ++num; u = tr[u][now]; }} else for(int i = 1; i <= len; ++i) { int now = s[i] - 'a' + 1; if(!tr[u][now]) tr[u][now] = ++num; u = tr[u][now];} return u; } il void Getfail() { queue<int> q; while(q.size()) q.pop(); for(int i = 1; i <= 26; ++i) if(tr[0][i]) q.push(tr[0][i]); while(q.size()) { int now = q.front(); q.pop(); for(int i = 1; i <= 26; ++i) { if(tr[now][i]) fail[tr[now][i]] = tr[fail[now]][i], q.push(tr[now][i]); else tr[now][i] = tr[fail[now]][i]; } } for(int i = 1; i <= num; ++i) e[fail[i]].push_back(i); } void dfs2(int x) {st[x] = ++fk; for(int v:e[x]) {dfs2(v);} ed[x] = fk; } void dfs1(int x, int fa) { dep[x] = dep[fa] + 1; f[x][0] = fa; for_1(i, 17) f[x][i] = f[f[x][i-1]][i-1]; for_edge(i, x){ int y = ver[i], z = edge[i]; if(y == fa) continue; fval[y] = z; dfs1(y, x); } } il int lca(int x, int y) { if(dep[x] < dep[y]) swap(x, y); for(int i = 17; i >= 0; --i) if(dep[f[x][i]] >= dep[y]) x = f[x][i]; if(x == y) return x; for(int i = 17; i >= 0; --i) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i]; return f[x][0]; } il int Bz(int x, int k) {for(int i = 17; i >= 0; --i) if((k>>i)&1) x = f[x][i]; return x; } il void KMP(int x, int y, int lc, int id, char *s) { int len = strlen(s + 1); int u = Bz(x, dep[x] - min(dep[x], dep[lc] + len - 1)), v = Bz(y, dep[y] - min(dep[y], dep[lc] + len - 1)); cnt = 0; int l = dep[u] + dep[v] - 2 * dep[lc]; int fu = u; while(fu != lc) s1[++cnt] = fval[fu] + 'a' - 1, fu = f[fu][0]; int tmp = 1, fv = v; while(fv != lc) s1[l - tmp + 1] = fval[fv] + 'a' - 1, fv = f[fv][0], ++tmp; net[0] = 0; net[1] = net[2] = 0; int k = 0, res = 0; for(int i = 2; i <= len; ++i) { while(k and s[k + 1] != s[i]) k = net[k]; if(s[k + 1] == s[i]) ++k; net[i] = k; } k = 0; for(int i = 1; i <= l; ++i) { while(k and s[k + 1] != s1[i]) k = net[k]; if(s[k + 1] == s1[i]) ++k; if(k >= len) ++res; } ans[id] += res; pos[id][0] = Insert(1, s); pos[id][1] = Insert(-1, s); if(x != u) {ID[x].push_back(id); ID[u].push_back(id); Ps[x].push_back(m_p(1, pos[id][1])); Ps[u].push_back(m_p(-1, pos[id][1])); } if(y != v) {ID[y].push_back(id); ID[v].push_back(id); Ps[y].push_back(m_p(1, pos[id][0])); Ps[v].push_back(m_p(-1, pos[id][0])); } } void dfs3(int x, int fa, int u) { Add(st[u], 1); for(int i = 0; i < Ps[x].size(); ++i) { int now = Ask(ed[Ps[x][i].second]) - Ask(st[Ps[x][i].second] - 1); ans[ID[x][i]] += Ps[x][i].first * now; } for_edge(i, x) { int y = ver[i], z = edge[i]; if(y == fa) continue; dfs3(y, x, tr[u][z]); } Add(st[u], -1); } signed main() { // freopen("memory.in","r",stdin); freopen("memory.out","w",stdout); n = re(), m = re(); for_1(i, n-1) {int x = re(), y = re(); char op; scanf("%s", &op); add(x, y, op - 'a' + 1); add(y, x, op - 'a' + 1); } dfs1(1, 1); for_1(i, m) { int x = re(), y = re(); scanf("%s", St + 1); if(x == y) continue; int lc = lca(x, y); KMP(x, y, lc, i, St);} Getfail(); dfs2(0); dfs3(1, 1, 0); for(int i = 1; i <= m; ++i) cout<<ans[i]<<endl; } /* 12 3 1 2 w 2 3 w 3 4 x 4 5 w 5 6 w 6 7 x 7 8 w 8 9 w 9 10 x 10 11 w 11 12 w 1 7 wwx 1 12 www 1 12 w */

__EOF__

本文作者Zwaire
本文链接https://www.cnblogs.com/Zwaire/p/16137691.html
关于博主:这个世界除了你,都知道我喜欢你
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Zwaire  阅读(35)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示