传送门


诈尸,主要是最近一直在刷水题感觉没有什么值得写的。

口胡好题,不建议写。

题解:

一句话说,将出现的情况分为在 u-LCA链上 和横跨LCA 分别统计。

在链上的可以直接建立正反AC自动机,然后树上DFS的同时AC自动机中DFS序+差分算一下出现次数即可。

考虑横跨LCA的情况,找出 u->LCA 的后缀能匹配的最长前缀和 LCA->v 的前缀能匹配的最长后缀。那么所有能匹配的前缀和后缀都是最长匹配前缀和后缀的border,分为log个等差数列,算一下凑成原串的方案数即可。

然后讲一下细节。

链上的部分是个人都会,不再赘述。

横跨LCA的情况,找出最长前后缀之后就是扩展欧几里得一下的事情,没有讨论价值。

麻烦的是找出可匹配的最长前后缀。

考虑如何找到 u->LCA 能匹配的最长前缀,后缀同理。

翻转一下串,考虑LCA->u 能匹配的反串的最长后缀。

首先哈希+树上倍增可以求出该串和反串某一后缀的LCP,加一个二分可以找到最长的LCP的位置,但是注意这个位置不一定能把后缀匹配完。
那么我们要找的可匹配后缀一定是这个后缀的border,需要用到原串的KMP数组,也是倍增处理一下跳即可。

至此,可以在时间 O(nlog⁡n+mlog⁡2n)O(n\log n+m\log^2n)O(nlogn+mlog2n) ,空间 O(mlog⁡m+nlog⁡n)O(m\log m+n\log n)O(mlogm+nlogn) 处理。

但是空间可以卡到 O(m+n)O(m+n)O(m+n) ,首先树上倍增可以换成树剖,先不断跳top,直到下一个位置能够完全和后缀匹配,然后在该点到该点的top中间进行二分即可。

而找可匹配后缀也不用对KMP进行倍增,记录一下等差数列是怎么拆的即可,与[HNOI2019]JOJO是一样的处理方式。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs constnamespace IO{inline char gc(){static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get_integer(){char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}
inline char ga(){char c;while(!isalpha(c=gc()));return c;}
inline int get_s(char *s){int len=0;char c;while(isspace(c=gc()));while(s[len++]=c,!isspace(c=gc()));return len;
}char obuf[(int)(1e7+7)],*oh=obuf,ch[23];
template<typename T>void print(T a,char c){if(a<0)*oh++='-',a=-a;int tl=0;do ch[++tl]=a%10; while(a/=10);while(tl)*oh++=ch[tl--]^48;*oh++=c;
}struct obuf_flusher{~obuf_flusher(){fwrite(obuf,1,oh-obuf,stdout);}}Flusher;}using IO::gi;
using IO::ga;
using IO::get_s;
using IO::print;using std::cerr;
using std::cout;cs int N=2e5+7,M=2e5+7;cs int M1=1e9+7,M2=1e9+9;
inline int add(int a,int b,int mod){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b,int mod){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b,int mod){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b,int mod){a+=b-mod,a+=a>>31&mod;}
inline void Dec(int &a,int b,int mod){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b,int mod){a=mul(a,b,mod);}
inline int power(int a,int b,int mod){int r=1;for(;b;b>>=1,Mul(a,a,mod))if(b&1)Mul(r,a,mod);return r;
}inline int ex_gcd(int a,int b,int &x,int &y){if(!b){x=1,y=0;return a;}int g=ex_gcd(b,a%b,y,x);y-=a/b*x;return g;
}inline int Inv(int a,int mod){int x,y;ex_gcd(mod,a,y,x);return x+(x>>31&mod);
}
int get_gr(cs int M){int phi=M-1;std::vector<int> p;for(int i=2;i*i<=phi;++i)if(phi%i==0){p.push_back(i);while(phi%i==0)phi/=i;}if(phi>1)p.push_back(phi),phi=M-1;for(int re gr=2;;++gr){bool flag=true;for(int t:p)if(power(gr,phi/t,M)==1){flag=false;break;}if(flag)return gr;}
}cs int g1=get_gr(M1),g2=get_gr(M2);
class Key{private:int x,y;public:Key(){}Key(int a):x(a),y(a){}Key(int _x,int _y):x(_x),y(_y){}friend Key operator+(cs Key &a,cs Key &b){return Key(add(a.x,b.x,M1),add(a.y,b.y,M2));}friend Key operator-(cs Key &a,cs Key &b){return Key(dec(a.x,b.x,M1),dec(a.y,b.y,M2));}friend Key operator*(cs Key &a,cs Key &b){return Key(mul(a.x,b.x,M1),mul(a.y,b.y,M2));}Key &operator+=(cs Key &b){Inc(x,b.x,M1);Inc(y,b.y,M2);return *this;}Key &operator-=(cs Key &b){Dec(x,b.x,M1);Dec(y,b.y,M2);return *this;}Key &operator*=(cs Key &b){Mul(x,b.x,M1);Mul(y,b.y,M2);return *this;}friend bool operator==(cs Key &a,cs Key &b){return a.x==b.x&&a.y==b.y;}friend bool operator!=(cs Key &a,cs Key &b){return a.x!=b.x||a.y!=b.y;}
};cs Key bse(g1,g2);
cs Key ibs(Inv(g1,M1),Inv(g2,M2));
Key pw[N],ip[N];struct AC_auto{int son[N][26];int tot;int fa[N],el[N],ps[M],nxt[N];int in[N],ou[N],tr[N],dfc;void ins(char *s,int len,int id){int u=0;for(int re i=1;i<=len;++i){int c=s[i]-'a';if(!son[u][c])son[u][c]=++tot;u=son[u][c];}ps[id]=u;}void build_ac(){std::queue<int> q;for(int re i=0;i<26;++i)if(son[0][i])q.push(son[0][i]);while(!q.empty()){int u=q.front();q.pop();for(int re c=0;c<26;++c)son[u][c]?(q.push(son[u][c]),fa[son[u][c]]=son[fa[u]][c]):(son[u][c]=son[fa[u]][c]);}for(int re i=1;i<=tot;++i)nxt[i]=el[fa[i]],el[fa[i]]=i;dfs(0);}void dfs(int u){in[u]=++dfc;for(int v=el[u];v;v=nxt[v])dfs(v);ou[u]=dfc;}int nx(int p,int c){return son[p][c];}void add(int p){for(p=in[p];p;p&=p-1)++tr[p];}void dec(int p){for(p=in[p];p;p&=p-1)--tr[p];}int qy(int p){p=ps[p];int l=in[p],r=ou[p]+1,res=0;for(;l<=dfc;l+=l&-l)res+=tr[l];for(;r<=dfc;r+=r&-r)res-=tr[r];return res;}
};struct atom{int l,r,d;};
struct KMP{int *nx,*d,*up,len;void build(char *s,int n){nx=new int[n+1];d=new int[n+1];up=new int[n+1];nx[0]=d[0]=up[0]=0;nx[1]=0,up[1]=1,d[1]=1;len=n;for(int re i=2,j=0;i<=len;++i){while(j&&s[j+1]!=s[i])j=nx[j];if(s[j+1]==s[i])++j;nx[i]=j,d[i]=i-j;if(d[i]==d[nx[i]])up[i]=up[nx[i]];else up[i]=i;}}
};
struct SA{int *sa,len;Key *vl;char *s;void build(char *s,int n){static int x[N],y[N];len=n;sa=new int[len+1];vl=new Key[len+1];vl[0]=Key(0);sa[0]=0;for(int re i=1;i<=n;++i)vl[i]=vl[i-1]+Key(s[i])*pw[i],x[i]=s[i],y[i]=i;for(int re i=1;i<=n;++i)x[i+n]=y[i+n]=0;int m=128;radix_sort(x,y,m,n);for(int re i=1,ct=0;ct<n;i<<=1){ct=0;for(int re j=n-i+1;j<=n;++j)y[++ct]=j;for(int re j=1;j<=n;++j)if(sa[j]>i)y[++ct]=sa[j]-i;radix_sort(x,y,m,n);y[sa[1]]=ct=1;for(int re i=1;i<=n;++i)std::swap(x[i],y[i]);for(int re j=2;j<=n;++j)x[sa[j]]=(y[sa[j]]==y[sa[j-1]]&&y[sa[j]+i]==y[sa[j-1]+i])?ct:++ct;m=ct;}this->s=new char[len+1];for(int re i=1;i<=len;++i)this->s[i]=s[i];}void radix_sort(int *x,int *y,int m,int n){static int bin[N];memset(bin+1,0,sizeof(int)*m);for(int re i=1;i<=n;++i)++bin[x[i]];for(int re i=1;i<=m;++i)bin[i]+=bin[i-1];for(int re i=n;i;--i)sa[bin[x[y[i]]]--]=y[i];}Key get(int l,int r){return (vl[r]-vl[l-1])*ip[l];}int lcp(int,int,int);bool chk(int,int,int);std::vector<atom> get(int,int,cs KMP &);
};AC_auto S,T;
KMP ori[M],rev[M];
SA sa_ori[M],sa_rev[M];int n,m,Q;
char s[N],t[N];int st[M],ed[M];
int el[N],nx[N+N],to[N+N],w[N+N],ec;
Key vl[N];int fa[N],d[N],top[N],pre[N];
int sz[N],son[N],dfn[N],ps[N],dfc;
void dfs1(int u,int p){d[u]=d[p]+1,fa[u]=p;sz[u]=1;for(int re e=el[u];e;e=nx[e])if(to[e]!=p){vl[to[e]]=Key(w[e])*pw[d[u]]+vl[u];dfs1(to[e],u),sz[u]+=sz[to[e]];pre[to[e]]=w[e];if(sz[to[e]]>sz[son[u]])son[u]=to[e];}
}void dfs2(int u,int tp){top[u]=tp,dfn[u]=++dfc,ps[dfn[u]]=u;if(son[u])dfs2(son[u],tp);for(int re e=el[u];e;e=nx[e])if(to[e]!=fa[u]&&to[e]!=son[u])dfs2(to[e],to[e]);
}Key tget(int u,int p){return (vl[u]-vl[p])*ip[d[p]];
}int jump(int u,int k){assert(k<d[u]);while(k>d[u]-d[top[u]]){k-=d[u]-d[top[u]]+1;u=fa[top[u]];}return ps[dfn[u]-k];
}int LCA(int u,int v){while(top[u]!=top[v])d[top[u]]<d[top[v]]?v=fa[top[v]]:u=fa[top[u]];return d[u]<d[v]?u:v;
}void str_build(char *s,AC_auto &S,KMP ori[],SA sa_ori[]){for(int re i=1;i<=m;++i){S.ins(s+st[i],ed[i]-st[i],i);ori[i].build(s+st[i],ed[i]-st[i]);sa_ori[i].build(s+st[i],ed[i]-st[i]);}S.build_ac();
}int U[M],V[M],P[M],id[M],ans[M];
struct Qry{int t,id;};
std::vector<Qry> vec[N];int sign(int x){return x<0?-1:(x>0?1:0);
}
void dfs_solve(int u,int p,int p1,int p2){S.add(p1),T.add(p2);for(auto t:vec[u])switch(std::abs(t.t)){case 1:ans[t.id]+=sign(t.t)*S.qy(id[t.id]);break;case 2:ans[t.id]+=sign(t.t)*T.qy(id[t.id]);break;}for(int re e=el[u];e;e=nx[e])if(to[e]!=p)dfs_solve(to[e],u,S.nx(p1,w[e]-'a'),T.nx(p2,w[e]-'a'));S.dec(p1),T.dec(p2);
}int solve(cs atom &v1,cs atom &v2,int len){if(v1.l+v2.l>len||v1.r+v2.r<len)return 0;int t1=(v1.r-v1.l)/(v1.d),t2=(v2.r-v2.l)/(v2.d);int x1,x2,y=len-v1.l-v2.l;int d1=v1.d,d2=v2.d,d=ex_gcd(d1,d2,x1,x2);if(y%d)return 0;int dt1=d2/d,dt2=d1/d;x1*=y/d,x2*=y/d;if(x1<0){int t=(-x1+dt1-1)/dt1;x1+=t*dt1;x2-=t*dt2;}else {int t=x1/dt1;x1-=t*dt1,x2+=t*dt2;}if(x1>t1||x2<0)return 0;int l1=0,r1=(t1-x1)/dt1,l2,r2=x2/dt2;if(x2-t2<0)l2=0;else l2=(x2-t2+dt2-1)/dt2;if(l1>r1||l2>r2||r1<l2||r2<l1)return 0;return std::min(r1,r2)-std::max(l1,l2)+1;
}int SA::lcp(int ps,int u,int p){if(u==p)return 0;int v=jump(u,d[u]-d[p]-1);if(d[u]-d[p]>len-sa[ps]+1)u=jump(u,d[u]-(d[p]+len-sa[ps]+1));int ct=0;while(u!=p){int up=d[top[u]]>d[v]?top[u]:v;if(tget(up,p)!=get(sa[ps],sa[ps]+d[up]-d[p]-1))u=fa[up];else break;}if(u==p)return 0;int up=d[top[u]]>d[v]?top[u]:v;int l=0,r=d[u]-d[up];while(l<r){int mid=(l+r)>>1;int q=::ps[dfn[u]-mid];if(tget(q,p)!=get(sa[ps],sa[ps]+d[q]-d[p]-1))l=mid+1;else r=mid;}return d[u]-d[p]-r;
}bool SA::chk(int ps,int u,int p){int l=lcp(ps,u,p);if(l==len)return false;if(l==len-sa[ps]+1)return true;if(l==d[u]-d[p])return false;return pre[jump(u,d[u]-d[p]-l-1)]>this->s[sa[ps]+l];
}std::vector<atom> SA::get(int u,int p,cs KMP &t){int l=1,r=len,ps=0;while(l<=r){int mid=(l+r)>>1;if(chk(mid,u,p))ps=mid,l=mid+1;else r=mid-1;}if(!ps)return {};l=lcp(ps,u,p);if(l==len-sa[ps]+1)ps=l;else {ps=sa[ps];ps=len-ps+1;while(ps>l)if(t.up[ps]>l)ps=t.nx[t.up[ps]];else {ps=t.up[ps]+(l-t.up[ps])/t.d[ps]*t.d[ps];}}std::vector<atom> vec;while(ps){vec.push_back({t.up[ps],ps,t.d[ps]});ps=t.nx[t.up[ps]];}return vec;
}
void Main(){n=gi();m=gi(),Q=gi();assert(m<=1e5); for(int re i=1;i<n;++i){int u=gi(),v=gi(),c=ga();nx[++ec]=el[u],el[u]=ec,to[ec]=v,w[ec]=c;nx[++ec]=el[v],el[v]=ec,to[ec]=u,w[ec]=c;}for(int re i=1;i<=m;++i){st[i]=ed[i-1]+1;ed[i]=st[i]+get_s(s+st[i]+1);std::reverse_copy(s+st[i]+1,s+ed[i]+1,t+st[i]+1);}pw[0]={1,1},ip[0]={1,1};for(int re i=1;i<=n;++i)pw[i]=pw[i-1]*bse,ip[i]=ip[i-1]*ibs;dfs1(1,0);dfs2(1,1);str_build(s,S,ori,sa_ori);str_build(t,T,rev,sa_rev);for(int re i=1;i<=Q;++i){int u=U[i]=gi(),v=V[i]=gi(),t=id[i]=gi();int p=P[i]=LCA(U[i],V[i]);if(d[u]-d[p]>=ed[t]-st[t]){vec[u].push_back({2,i});vec[jump(u,d[u]-d[p]-ed[t]+st[t]+1)].push_back({-2,i});}if(d[v]-d[p]>=ed[t]-st[t]){vec[v].push_back({1,i});vec[jump(v,d[v]-d[p]-ed[t]+st[t]+1)].push_back({-1,i});}}dfs_solve(1,0,0,0);for(int re i=1;i<=Q;++i){auto v1=sa_rev[id[i]].get(U[i],P[i],ori[id[i]]);auto v2=sa_ori[id[i]].get(V[i],P[i],rev[id[i]]);for(auto t1:v1)for(auto t2:v2)ans[i]+=solve(t1,t2,ed[id[i]]-st[id[i]]);print(ans[i],'\n');}
}inline void file(){#ifdef zxyoifreopen("tree.in","r",stdin);freopen("tree.out","w",stdout);
#endif
}signed main(){file();Main();return 0;}

【CF917E】Upside Down(哈希二分)(后缀数组)(AC自动机)相关推荐

  1. POJ - 3450 Corporate Identity(二分+后缀数组)

    题目链接:点击查看 题目大意:给出n个字符串,求出n个字符串中最长的公共子串,如果没有,输出IDENTITY LOST 题目分析:可以直接用二分+后缀数组来做,先将n个字符串连接起来,中间用一个不同的 ...

  2. HDU4080 Stammering Aliens(二分 + 后缀数组)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4080 Description Dr. Ellie Arroway has establish ...

  3. POJ1226 Substrings(二分+后缀数组)

    题意:给n个字符串,求最长的子串,满足它或它的逆置出现在所有的n个字符串中. 把n个字符串及其它们的逆置拼接,中间用不同字符隔开,并记录suffix(i)是属于哪个字符串的: 跑后缀数组计算heigh ...

  4. POJ - 3261 Milk Patterns(二分+后缀数组)

    题目链接:点击查看 题目大意:给出一个字符串,以及一个k,现在求出现次数大于等于k次的最大可重叠子串的长度 题目分析:可以说是后缀数组的模板题目了吧..直接跑出height数组,因为height数组代 ...

  5. POJ - 1743 Musical Theme(二分+后缀数组+差分数组)

    题目链接:点击查看 题目大意:给出n个连续的数字组成的序列,现在要求出其中两个不重叠的字序列,满足两个子序列"相似",相似的定义是两个子序列当且仅当长度相等并且每一位的数字差都相等 ...

  6. HDU5853 Jong Hyok and String(二分 + 后缀数组)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5853 Description Jong Hyok loves strings. One da ...

  7. 2019ICPC(徐州) - Colorful String(哈希+二分+动态规划/回文自动机)

    题目链接:点击查看 题目大意:给出一个字符串,询问该字符串中的所有回文子串中,各有多少不同的字母 题目分析:这个题题意很简单,在比赛的时候看到字符串第一反应是哈希,哈希+暴力+线段树果不其然的T掉了. ...

  8. POJ - 3294 Life Forms(二分+后缀数组)

    题目链接:点击查看 题目大意:给出n个字符串,求出至少在n/2个字符串中出现的最长的公共子串,如果没有,输出"?" 题目分析:和poj3450几乎一样的题目,只不过最长公共子串出现 ...

  9. 后缀数组(未完待续)

    后缀数组 简介 后缀数组(Suffix Array, SA)是一种在字符串问题中很实用的工具,其主要作用是求多模板匹配和最长公共前缀(LCP).与 AC自动机 预先处理模板串不同,后缀数组在进行多模板 ...

  10. Musical Theme pku1743 (后缀数组)

    Musical Theme(后缀数组) 题意: n个数,选取一段子序列,满足以下条件: 1.长度至少为5 2.在数列中其他位置出现过(允许转置) 3.与其他位置出现的不重叠 转置:将恒定的正或负值添加 ...

最新文章

  1. 链接SQL Server服务器
  2. QueueToStack
  3. hibernate教程--常用配置和核心API
  4. TypeScript 里 tsconfig.json 文件的作用
  5. 《布莱克智讯之声》公众号文章汇总
  6. java下载的文件不完整_JAVA 解决FTP下载文件不完整问题
  7. 使用计算列提高查询性能
  8. 原版windows下载地址
  9. mysql过程的写法_mysql存储过程的具体写法
  10. 永久关闭windows的自动更新
  11. CAD看图软件查看CAD图纸
  12. 【总结】最好的CV学习小组,超200个课时+10个方向+30个项目,从理论到实践全部系统掌握...
  13. 用人篇-曾国藩家书整理
  14. STM32中断优先级分组概念
  15. 终结吧!机器学习的数学焦虑_机器人来了!
  16. 如果你身边有程序员 今天对他好一点
  17. 阿龙学堂-VUE面试总结
  18. Codeforces 769B 暴力
  19. java添加边框_Java如何为边框添加标题?
  20. php富友接口对接http请求

热门文章

  1. (十八)用JAVA编写MP3解码器——迷你播放器
  2. java实现24点计算
  3. Xinetd服务的安装与配置【转载】
  4. warpAffine函数解析
  5. skip-gram 学习笔记
  6. Android 仿QQ退出(点击返回键不退出app,点击icon直接进入上次退出的页面)
  7. NRF52832之蓝牙MAC地址修改
  8. mysql优化之query_cache_type的DEMAND参数介绍
  9. 【线代】矩阵的秩和线性方程组的解的情况
  10. 电脑无法输出4K信号怎么办