相关链接
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4231
数据生成器:http://paste.ubuntu.com/24366714/
神犇题解:http://www.cnblogs.com/clrs97/p/5467637.html
解题报告
首先我们如果最终一个串出现的位置会越过$LCA$
那么我们可以把这一部分的情况单独拿出来,暴力跑$KMP$
剩下就是单纯地从根节点向下,或者向上的路径中出现了多少次
这不难让我们想到广义后缀自动机,但似乎这题并不能用
考虑另一个方法,把所有模式串建成AC自动机
然后在原树上$DFS$,进入一个点时将其在AC自动机对应的结点权值$+1$
退出来的时候将其$-1$,那么我们在需要询问的时候统计一下子树的权值和就可以了
总时间复杂度:$O(n \log n + \sum |S|)$
Code
#include<bits/stdc++.h> #define LL long long using namespace std; const int N = 100009; const int M = 600009; int n,m,head[N],nxt[M],to[M],cost[M],U[N]; int pp[N][2],ans[N],dep[N],fa[N][20],C[N]; vector<pair<int,int> > qry[N]; class AC_Automaton{ int dfs_cnt,ch[M][26],fail[M],in[M],out[M]; queue<int> que; vector<int> sn[M]; struct Fenwick_Tree{ int sum[M],sz; inline int lowbit(int x) {return x & -x;} inline void modify(int w, int delta) { for (int i=w;i<=sz;i+=lowbit(i)) sum[i] += delta; } inline int query(int l, int r) { int ret = 0; l--; for (int i=l;i;i-=lowbit(i)) ret -= sum[i]; for (int i=r;i;i-=lowbit(i)) ret += sum[i]; return ret; } }BIT; public: inline void build() { for (int i=0;i<26;i++) ch[0][i]=1; que.push(1); fail[1] = 0; while (!que.empty()) { int w = que.front(); que.pop(); sn[fail[w]].push_back(w); for (int i=0;i<26;i++) { if (ch[w][i]) { que.push(ch[w][i]); fail[ch[w][i]] = ch[fail[w]][i]; } else ch[w][i] = ch[fail[w]][i]; } } DFS(1); BIT.sz = dfs_cnt; } inline int insert(char *s) { static int cnt = 1; int w = 1, len = strlen(s+1); for (int i=1,c;i<=len;i++) { if (!ch[w]-'a']) ch[w] = ++cnt; w = ch[w]; } return w; } inline int query(int p) { return BIT.query(in[p], out[p]); } inline void modify(int p, int delta) { BIT.modify(in[p], delta); } inline int move(int w, int c) { return ch[w]; } private: void DFS(int w) { in[w] = ++dfs_cnt; for (int i=sn[w].size()-1;~i;i--) if (!in[sn[w][i]]) DFS(sn[w][i]); out[w] = dfs_cnt; } }ac; inline int read() { char c=getchar(); int f=1,ret=0; while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();} while (c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();} return ret * f; } inline void AddEdge(int u, int v, int c) { static int E = 1; cost[E+1] = cost[E+2] = c; to[++E] = v; nxt[E] = head[u]; head[u] = E; to[++E] = u; nxt[E] = head[v]; head[v] = E; } inline int LCA(int a, int b) { if (dep[a] < dep[b]) swap(a, b); for (int j=19;~j;j--) if (dep[fa[a][j]] >= dep[b]) a = fa[a][j]; if (a == b) return a; for (int j=19;~j;j--) if (fa[a][j] != fa[b][j]) a = fa[a][j], b = fa[b][j]; return fa[a][0]; } void pre(int w, int f) { fa[w][0] = f; dep[w] = dep[f] + 1; for (int i=head[w];i;i=nxt[i]) if (to[i] != f) C[to[i]] = cost[i], pre(to[i], w); } void solve(int w, int p) { for (int i=qry[w].size()-1,f;~i;i--) { if (qry[w][i].first>0) f = 1; else f = -1, qry[w][i].first *= -1; ans[qry[w][i].first] += ac.query(pp[qry[w][i].first][qry[w][i].second]) * f; } for (int i=head[w],tmp;i;i=nxt[i]) { if (dep[to[i]] > dep[w]) { tmp = ac.move(p, cost[i]); ac.modify(tmp, 1); solve(to[i], tmp); ac.modify(tmp, -1); } } } inline int dif(int &u, int &v, int lca, char *s, int len) { static char ss[M]; static int NXT[M]; int tot = 0, TOT; int w = u, l = dep[u] - dep[lca] - len + 1, ret = 0; if (l > 0) {for (int j=0;l;l>>=1,++j) if (l&1) w = fa[w][j]; u = w;} while (w != lca) ss[++tot] = C[w] + 'a', w = fa[w][0]; w = v; l = dep[v] - dep[lca] - len + 1; if (l > 0) {for (int j=0;l;l>>=1,++j) if (l&1) w = fa[w][j]; v = w;} TOT = (tot += dep[w] - dep[lca]); while (w != lca) ss[tot--] = C[w] + 'a', w = fa[w][0]; for (int i=1,w;i<=len;i++) { for (w=NXT[i];w&&s[w+1]!=s[i+1];w=NXT[w]); NXT[i+1] = w + (s[w+1] == s[i+1]); } for (int i=1,w=0;i<=TOT;i++) { for (;w&&s[w+1]!=ss[i];w=NXT[w]); w += s[w+1] == ss[i]; ret += w == len; } return ret; } int main() { n = read(); m = read(); for (int i=1,u,v;i<n;i++) { u = read(); v = read(); char c[2]; scanf("%s",c); AddEdge(u, v, c[0] - 'a'); } pre(1, 1); for (int j=1;j<=19;j++) for (int i=1;i<=n;i++) fa[i][j] = fa[fa[i][j-1]][j-1]; char pat[300009]; for (int i=1,u,v,lca,ll,p1,p2;i<=m;i++) { U[i] = u = read(); v = read(); lca = LCA(u, v); scanf("%s",pat+1); pp[i][0] = ac.insert(pat); ll = strlen(pat+1); qry[u].push_back(make_pair(i,1)); qry[v].push_back(make_pair(i,0)); ans[i] += dif(u, v, lca, pat, ll); qry[u].push_back(make_pair(-i,1)); qry[v].push_back(make_pair(-i,0)); for (int l=1,r=ll;l<r;l++,r--) swap(pat[l], pat[r]); pp[i][1] = ac.insert(pat); } ac.build(); solve(1, 1); for (int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
It’s great that you are getting ideas from this post
as well as from our discussion made here.
I’m gone to tell my little brother, that he should also go to see this
website on regular basis to obtain updated from latest gossip.
I really like your blog.. very nice colors & theme. Did you create this website yourself or did you hire
someone to do it for you? Plz reply as I’m looking to design my own blog and would like to know where u got this from.
cheers
Hi there to all, because I am in fact eager of reading this blog’s post to be updated regularly.
It includes pleasant data.
Every weekend i used to pay a visit this website, as i wish for
enjoyment, as this this web site conations actually pleasant funny material too.
I visited many web pages except the audio quality for audio songs existing
at this web page is really marvelous.
This is my first time pay a quick visit at here and i am actually happy to read everthing at alone place.
Hello there! I know this is kinda off topic but I was wondering
if you knew where I could get a captcha plugin for my comment form?
I’m using the same blog platform as yours and I’m having trouble finding one?
Thanks a lot!
Excellent weblog here! Also your site a lot up very fast!
What web host are you the usage of? Can I get your associate
link to your host? I want my website loaded up as quickly as yours lol
Heya i am for the first time here. I came across this board and I find It truly
useful & it helped me out much. I hope to give something back and help others like you aided me.
Thank you for the auspicious writeup. It in fact was a amusement account it. Look advanced to more added agreeable from you! However, how could we communicate?
Thanks very interesting blog!
I must thank you for the efforts you’ve put in writing this website.
I really hope to see the same high-grade content from you in the future as well.
In truth, your creative writing abilities has inspired me to get my very own website now ;
)
I just like the valuable information you provide for
your articles. I’ll bookmark your blog and test again right here
frequently. I am slightly certain I’ll learn lots of new stuff right
right here! Good luck for the next!
That is really interesting, You’re an excessively professional blogger.
I’ve joined your rss feed and stay up for in search of more of your excellent post.
Additionally, I’ve shared your web site in my social networks
obviously like your web site however you need to take a look
at the spelling on several of your posts.
Several of them are rife with spelling problems and I in finding
it very bothersome to inform the truth nevertheless I’ll certainly come back again.
Good information. Lucky me I found your blog by
chance (stumbleupon). I have bookmarked it for later!
Great website you have here but I was wondering if you knew of any message boards that cover the same topics talked about in this article?
I’d really like to be a part of community
where I can get suggestions from other experienced individuals
that share the same interest. If you have any recommendations, please let me know.
Bless you!
Good respond in return of this matter with firm arguments and explaining all concerning that.
Hello, Neat post. There is a problem along with your site in web explorer, would
test this? IE still is the market chief and
a huge section of other people will pass over your magnificent writing due to this problem.
This site was… how do you say it? Relevant!! Finally I have found something which helped me.
Thanks!
Yeah bookmaking this wasn’t a bad determination great post! .