【CTSC2010】珠宝商【后缀自动机】【点分治】【根号分治】

题意:给一棵 nnn 个点的树,每个点有个字符,另给一个长度为 mmm 的特征串,求树上 n2n^2n2 条有向路径在特征串中出现的次数之和。

n,m≤5×104n,m\leq 5\times 10^4n,m5×104

看到母串先建 SAM (bushi

树上路径统计问题,考虑点分治。

对当前分治中心,我们希望求出所有经过分治中心的路径的贡献。因为是计数问题,同一个子树的可以容斥掉,所以这不会成为思维瓶颈。

考虑求出特征串上每个位置作为分治中心的匹配点的方案数,我们只需要求出这个位置结束的后缀以及开始的前缀总共可以匹配多少个以分治中心为终点或起点的路径。两个是同理的,考虑前面一个。

我们然后从分治中心开始 dfs,记录从当前点到分治中心的路径构成的串在 SAM 上的位置。如果这个串不是其等价类中最长的,那么判断一下加入一个字符后是否是等价类中长度多 111 的串,不是就返回。

如果是等价类中最长的,前面加一个字符后可(yi)能(ding)会对应多个状态。在 SAM 上预处理出一个 nxt(p,c)nxt(p,c)nxt(p,c),表示 ppp 号结点代表的最长串前面加上字符 ccc 后到达的状态,没有为 000。每访问一个位置就让该结点的计数器 +1+1+1

然后我们要求某个位置结尾的后缀被访问次数之和,也就是到根的路径和,做一个树上前缀和即可。

这样对一个大小为 sizsizsiz 的连通块复杂度是 O(siz+m)\Omicron(siz+m)O(siz+m),在 sizsizsiz 很小时显得浪费。

考虑根号分治,当 siz<nsiz<\sqrt nsiz<n 时直接 O(siz2)\Omicron(siz^2)O(siz2) 暴力。这样点分治只会递归一半的层数,暴力的次数也只有 O(n)\Omicron(\sqrt n)O(n)。总复杂度 O((n+m)n)\Omicron((n+m)\sqrt n)O((n+m)n)

注意容斥的时候也要根号分治,否则会被菊花图卡。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <cmath>
#define MAXN 100005
using namespace std;
typedef long long ll;
int n,m,B;
inline int read()
{int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
struct SAM
{char s[MAXN];int ch[MAXN][26],nxt[MAXN][26],fa[MAXN],len[MAXN],pos[MAXN],rt[MAXN],sum[MAXN],siz[MAXN],tot,las;void insert(int c,int k){int cur=++tot,p=las;len[cur]=len[p]+1;for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;if (!p) fa[cur]=1;else{int q=ch[p][c];if (len[q]==len[p]+1) fa[cur]=q;else{int _q=++tot;len[_q]=len[p]+1;fa[_q]=fa[q],fa[q]=fa[cur]=_q;memcpy(ch[_q],ch[q],sizeof(ch[q]));for (;ch[p][c]==q;p=fa[p]) ch[p][c]=_q;	}	} ++siz[pos[k]=las=cur];}int a[MAXN],c[MAXN];void build(){tot=las=1;for (int i=1;i<=m;i++) insert(s[i]-'a',i);for (int i=1;i<=tot;i++) ++c[len[i]];for (int i=1;i<=tot;i++) c[i]+=c[i-1];for (int i=1;i<=tot;i++) a[c[len[i]]--]=i;for (int i=1;i<=m;i++) rt[pos[i]]=i;for (int i=tot;i>=1;i--) rt[fa[a[i]]]=rt[a[i]],siz[fa[a[i]]]+=siz[a[i]];for (int i=2;i<=tot;i++) nxt[fa[i]][s[rt[i]-len[fa[i]]]-'a']=i;}int getnxt(int p,int l,int c){if (l<len[p]) return c==s[rt[p]-l]-'a'? (++sum[p],p):0;return ++sum[p=nxt[p][c]],p;}inline void clear(){for (int i=1;i<=tot;i++) sum[i]=0;}inline void getsum(int* ans){for (int i=2;i<=tot;i++) sum[a[i]]+=sum[fa[a[i]]];for (int i=1;i<=m;i++) ans[i]=sum[pos[i]];}
}S,T;
ll ans;
vector<int> e[MAXN];
char s[MAXN];
int vis[MAXN],fa[MAXN];
int siz[MAXN],maxp[MAXN],rt;
void findrt(int u,int f,int sum)
{siz[u]=1,maxp[u]=0;for (int i=0;i<(int)e[u].size();i++)if (!vis[e[u][i]]&&e[u][i]!=f){findrt(e[u][i],u,sum);siz[u]+=siz[e[u][i]];maxp[u]=max(maxp[u],siz[e[u][i]]);}maxp[u]=max(maxp[u],sum-siz[u]);if (maxp[u]<maxp[rt]) rt=u;
}
void dfs(SAM& S,int u,int f,int l,int p)
{siz[u]=1,p=S.getnxt(p,l,s[u]-'a');for (int i=0;i<(int)e[u].size();i++)if (!vis[e[u][i]]&&e[u][i]!=f)dfs(S,e[u][i],u,l+1,p),siz[u]+=siz[e[u][i]];
}
vector<int> lis;
void dfs(int u,int f)
{lis.push_back(u),fa[u]=f;for (int i=0;i<(int)e[u].size();i++)if (!vis[e[u][i]]&&e[u][i]!=f)dfs(e[u][i],u);
}
void dfs(int u,int f,int p,int v)
{if (!(p=S.ch[p][s[u]-'a'])) return;ans+=v*S.siz[p];for (int i=0;i<(int)e[u].size();i++)if (!vis[e[u][i]]&&e[u][i]!=f)dfs(e[u][i],u,p,v);
}
int a[MAXN],b[MAXN];
void calc()
{S.clear(),T.clear();dfs(S,rt,0,0,1),dfs(T,rt,0,0,1);S.getsum(a),T.getsum(b);for (int i=1;i<=m;i++) ans+=(ll)a[i]*b[m-i+1];for (int i=0;i<(int)e[rt].size();i++)if (!vis[e[rt][i]]){if (siz[e[rt][i]]<B){lis.clear(),dfs(e[rt][i],rt);for (int j=0;j<(int)lis.size();j++){int v=lis[j],p=1;while (fa[v]) p=S.ch[p][s[v]-'a'],v=fa[v];p=S.ch[p][s[rt]-'a'];dfs(e[rt][i],0,p,-1);}}else{S.clear(),T.clear();dfs(S,e[rt][i],0,1,S.ch[1][s[rt]-'a']),dfs(T,e[rt][i],0,1,T.ch[1][s[rt]-'a']);S.getsum(a),T.getsum(b);for (int i=1;i<=m;i++) ans-=(ll)a[i]*b[m-i+1];}}
}
void calcV()
{lis.clear(),dfs(rt,0);for (int i=0;i<(int)lis.size();i++) dfs(lis[i],0,1,1);
}
void solve()
{int u=rt;vis[u]=1;calc();for (int i=0;i<(int)e[u].size();i++)if (!vis[e[u][i]]){rt=0,findrt(e[u][i],0,siz[e[u][i]]);siz[e[u][i]]<B? calcV():solve();}
}
int main()
{maxp[0]=0x7fffffff;B=sqrt(n=read()),m=read();for (int i=1;i<n;i++){int u,v;u=read(),v=read();e[u].push_back(v),e[v].push_back(u);}scanf("%s",s+1);scanf("%s",S.s+1);for (int i=1;i<=m;i++) T.s[m-i+1]=S.s[i];S.build(),T.build();findrt(1,0,n);solve();cout<<ans<<'\n';return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314794.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Azure云原生构建博客是怎样一种体验?(下篇)

点击上方蓝字关注“汪宇杰博客”接上篇《使用Azure云原生构建博客是怎样一种体验&#xff1f;&#xff08;上篇&#xff09;》DNSAzure DNS 是一套分布全球的域名解析服务。具有超高可用性和接近实时的记录更新及生效速度。我的博客也使用了这项服务。Azure 现在可以提供域名注…

2021牛客暑期多校训练营1 G Game of Swapping Numbers 思维 + 巧妙的转换

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你两个数组A,BA,BA,B&#xff0c;你可以选择AAA的两个位置i,j,i<ji,j,i<ji,j,i<j交换Ai,AjA_i,A_jAi​,Aj​&#xff0c;需要交换正好kkk次&#xff0c;问你最大的∑i1n∣Ai−Bi∣\sum_{i1}^n|A_…

.NET Core 3.0之深入源码理解HttpClientFactory(一)

写在前面创建HttpClient实例的时候&#xff0c;在内部会创建HttpMessageHandler链&#xff0c;我们知道HttpMessageHandler是负责建立连接的抽象处理程序&#xff0c;所以HttpClient的维护实际上就是维护HttpMessageHandler的使用&#xff0c;释放HttpClient并不会及时释放连接…

WTM 构建DotNetCore开源生态,坐而论道不如起而行之

作为一个8岁开始学习编程&#xff0c;至今40岁的老程序员&#xff0c;这辈子使用过无数种语言&#xff0c;从basic开始&#xff0c;到pascal, C, C&#xff0c;到后来的 java, c#,perl,php,再到现在流行的python。小时候的我总觉得多掌握一门语言&#xff0c;我的技术能力就又前…

【WC2014】时空穿梭【组合数】【莫比乌斯反演】【整除分块】【暴力多项式】

题意&#xff1a;TTT 组数据&#xff0c;给一个 nnn 维空间&#xff0c;第 iii 维大小为 [1,mi]∩Z[1,m_i]\cap \Z[1,mi​]∩Z&#xff0c;求大小为 ccc 的严格偏序上升的共线点集个数。答案模 100071000710007。 T≤100,n≤11,m≤105,c≤20T\leq 100,n\leq 11,m\leq 10^5,c\le…

2021牛客暑期多校训练营1 H Hash Function FFT\NTT

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个数组aaa&#xff0c;你需要找一个最小的模数xxx&#xff0c;使得aaa中每个数都模上xxx之后互不相同。 n≤5e5,ai≤5e5,ai!ajn\le5e5,a_i\le5e5,a_i!a_jn≤5e5,ai​≤5e5,ai​!aj​ 思路&#xff1a…

架构杂谈《六》

超时处理模式在服务化或者微服务架构里&#xff0c;传统的整体应用拆分成多个职责单一的微服务&#xff0c;微服务之间通过某种网络通信协议互相通信和交互&#xff0c;完成特定的功能&#xff0c;然而由于网络通信的不稳定&#xff0c;在设计系统时必须考虑到对网络通信的容错…

【BZOJ4543】Hotel加强版【神仙树形dp】【长链剖分】

题意&#xff1a;给一棵 nnn 个点的树&#xff0c;求两两距离相等的三元组个数。 n≤105n\leq 10^5n≤105 显然相当于是找一个点到这三个点距离相等。子树内和子树外到当前点的距离为某个值的点的个数可以长链剖分快速得到&#xff0c;但统计答案非常棘手。 接下来是个鬼才想…

hdu 6962 I love tree 线段树维护二次函数

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你nnn个点的一颗树&#xff0c;有mmm次询问&#xff0c;每次询问有两个操作&#xff1a; (1)(1)(1)将[a,b][a,b][a,b]路径上的点依次加上12,22,32,...,len2,lenpath(a,b)1^2,2^2,3^2,...,len^2,lenpath(a,…

基于surging 的stage组件设计,谈谈我眼中的微服务

一、前言surging 开源地址&#xff1a;https://github.com/dotnetcore/surging随着业务的发展&#xff0c;并发量的增多&#xff0c;业务的复杂度越来越大&#xff0c;对于系统架构能力要求越来越高&#xff0c;这时候微服务的设计思想应运而生&#xff0c;但是对于微服务需要引…

【PKUSC2018】星际穿越【结论】【倍增dp】

题意&#xff1a;有一张边权为 111 的无向图&#xff0c;对 i∈[2,n]i\in [2,n]i∈[2,n]&#xff0c;iii 与 [li,i−1][l_i,i-1][li​,i−1] 间有边。 qqq 次询问 l,r,xl,r,xl,r,x&#xff0c;表示 xxx 与 [l,r][l,r][l,r] 中的所有点的最短路长度的平均值&#xff0c;其中 l&l…

HDU - 6971 K - I love max and multiply sosdp

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 直接求i&j>ki\And j>ki&j>k不是很好求&#xff0c;所以转换成i&jki\And jki&jk的情况。 考虑对a,ba,ba,b求一遍超集&#xff0c;让后从[0,n−1][0,n-1][0,n−1]扫…

推荐10个技术圈优质的公众号大号

公众号有很多但需要什么只有自己知道本次筛选了一批技术圈优质的公众号&#xff0c;主要与python、人工智能、机器学习、技术人生相关希望对你有所帮助!▼★长按二维码&#xff0c;选择“识别二维码”进行关注。▲长按二维码&#xff0c;识别关注简介&#xff1a;Python爱好者社…

【SDOI2013】项链【莫比乌斯反演】【Polya定理】【递推式求通项】【数论】

题意&#xff1a;TTT 组数据&#xff0c;每组给定 n,an,an,a&#xff0c;求满足下列条件的项链数量&#xff1a; 有 nnn 个珠子。每个珠子上有三个 [1,a]∩Z[1,a]\cap \Z[1,a]∩Z 的数&#xff0c;且三个数 gcd⁡\gcdgcd 为 111。相邻两个珠子不同。 珠子旋转、翻转同构&…

HDU - 6955 Xor sum tire树 + 贪心

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个数列aaa&#xff0c;你需要找出来一个长度最小且左端点最靠前的区间&#xff0c;使其异或和≥k\ge k≥k。 n≤1e5,0≤ai,k<230n\le1e5,0\le a_i,k<2^{30}n≤1e5,0≤ai​,k<230 思路&#…

使用Kubeadm创建k8s集群之部署规划(三十一)

前言 上一篇我们讲述了使用Kubectl管理k8s集群&#xff0c;那么接下来&#xff0c;我们将使用kubeadm来启动k8s集群。部署k8s集群存在一定的挑战&#xff0c;尤其是部署高可用的k8s集群更是颇为复杂&#xff08;后续会讲&#xff09;。因此本教程会在部署的过程中穿插讲…

HDU - 6967 G I love data structure 线段树维护矩阵 + 细节

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你两个长度为nnn的数组a,ba,ba,b&#xff0c;你需要完成如下四种操作&#xff1a; 思路&#xff1a; 思路还是比较简单的&#xff0c;首先建一颗线段树&#xff0c;线段树中维护a,b,a2,b2,aba,b,a^2,b^…

【APIO2016】Fireworks【闵可夫斯基和】【凸包向量和】【可并堆】

题意&#xff1a;给一棵带边权的树&#xff0c;可以花费 111 的代价把一条边的边权修改 111&#xff0c;一条边可以修改多次&#xff0c;求使得根到叶子距离相等的最小代价。 n≤3105n\leq 3\times 10^5n≤3105 先暴力 dp 设 f(u,k)f(u,k)f(u,k) 表示 uuu 到子树内所有叶子距…

荐读|属性与可直接访问的数据成员之间应该如何选

写在前面在书写C#代码的时候你是否有过这样的经历&#xff1a;经常混用属性以及公有的数据成员。毕竟他们的用法基本一致&#xff0c;对于使用来说好像没什么区别啊。其实我也经常使用类的公有的数据成员来定义一些常量&#xff0c;为了简单&#xff0c;在一些仅仅需要对外暴露…

【TC10738】TheContest【Hall 定理】【贪心】【二分图匹配】

题意&#xff1a;给 nmn\times mnm 的表格填入 [1,max⁡(n,m)][1,\max(n,m)][1,max(n,m)] 的数&#xff0c;每行每列不能重复&#xff0c;且字典序最小。 n,m≤50n,m\leq 50n,m≤50 数据范围很小&#xff0c;所以是多项式就能过。 考虑每个位置从小到大依次填值&#xff0c;判…