洛谷P4218 [CTSC2010]珠宝商(后缀自动机+点分治)
这题思路太清奇了……->题解
//minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getchar()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getchar());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,:;}
const int N=1e5+;
char str[N],s[N];
ll ans=;
int ver[N],Next[N],head[N],tot=;
int sqr,id1[N],id2[N];
inline void add(int u,int v){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
}
int vis[N],rt,son[N],sz[N],size,n,m;
struct SAM{
int rt,last,tot,ch[N][],fa[N],l[N],cnt[N];
int s[N],tag[N],son[N][],le[N];
SAM(){rt=last=tot=;}
int ins(int c){
int p=last,np=++tot;last=np,le[np]=l[np]=l[p]+,cnt[np]=;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=rt;
else{
int q=ch[p][c];
if(l[q]==l[p]+) fa[np]=q;
else{
int nq=++tot;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
l[nq]=l[p]+,le[nq]=le[q];
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
return last;
}
int a[N],c[N];
void calc(){
for(int i=;i<=tot;++i) ++c[l[i]];
for(int i=;i<=tot;++i) c[i]+=c[i-];
for(int i=tot;i;--i) a[c[l[i]]--]=i;
for(int i=tot,p;i>=;--i){
p=a[i];
cnt[fa[p]]+=cnt[p];
son[fa[p]][s[le[p]-l[fa[p]]]]=p;
}
}
void mark(int u,int fa,int now,int len){
if(!now) return;
if(len==l[now]) now=son[now][str[u]-'a'];
else if(s[le[now]-len]!=str[u]-'a') now=;
if(!now) return;
++tag[now];
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa&&!vis[v]) mark(v,u,now,len+);
}
}
inline void push(){for(int i=;i<=tot;++i) tag[a[i]]+=tag[fa[a[i]]];}
}sam1,sam2;
void findrt(int u,int fa){
sz[u]=,son[u]=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa&&!vis[v])
findrt(v,u),sz[u]+=sz[v],cmax(son[u],sz[v]);
}
cmax(son[u],size-sz[u]);
if(!rt||son[u]<son[rt]) rt=u;
}
int num=,g[N];
void get(int u,int fa){
g[++num]=u;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa&&!vis[v]) get(v,u);
}
}
void getsum(int u,int fa){
++size;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa&&!vis[v]) getsum(v,u);
}
}
void dfs(int u,int fa,int now){
now=sam1.ch[now][str[u]-'a'];
if(!now) return;
ans+=sam1.cnt[now];
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa&&!vis[v]) dfs(v,u,now);
}
}
void work(int u,int fa,int op){
for(int i=;i<=sam1.tot;++i) sam1.tag[i]=;
for(int i=;i<=sam2.tot;++i) sam2.tag[i]=;
int to=str[fa]-'a';
if(fa) sam1.mark(u,fa,sam1.son[][to],),sam2.mark(u,fa,sam2.son[][to],);
else sam1.mark(u,fa,,),sam2.mark(u,fa,,);
sam1.push(),sam2.push();
for(int i=;i<=m;++i) ans+=1ll*op*sam1.tag[id1[i]]*sam2.tag[id2[m-i+]];
}
void solve(int u){
if(size<=sqr){
num=,get(u,);
for(int i=;i<=num;++i) dfs(g[i],,sam1.rt);
return;
}
vis[u]=,work(u,,);
for(int i=head[u];i;i=Next[i])
if(!vis[ver[i]]) work(ver[i],u,-);
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(vis[v]) continue;
size=,getsum(v,u);
rt=,findrt(v,u);
solve(rt);
}
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=read();
for(int i=,u,v;i<n;++i)
u=read(),v=read(),add(u,v),add(v,u);
scanf("%s",str+),scanf("%s",s+);
for(int i=;i<=m;++i) sam1.s[i]=s[i]-'a',id1[i]=sam1.ins(s[i]-'a');
reverse(s+,s++m);
for(int i=;i<=m;++i) sam2.s[i]=s[i]-'a',id2[i]=sam2.ins(s[i]-'a');
sam1.calc(),sam2.calc();
rt=,son[]=n+,size=n,sqr=sqrt(n);
findrt(,),solve(rt);
printf("%lld\n",ans);
return ;
}
洛谷P4218 [CTSC2010]珠宝商(后缀自动机+点分治)的更多相关文章
- 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)
题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...
- P4218 [CTSC2010]珠宝商
P4218 [CTSC2010]珠宝商 神题... 可以想到点分治,细节不写了... (学了个新姿势,sam可以在前面加字符 但是一次点分治只能做到\(O(m)\),考虑\(\sqrt n\)点分治, ...
- 洛谷-P5357-【模板】AC自动机(二次加强版)
题目传送门 -------------------------------------- 过年在家无聊补一下这周做的几道AC自动机的模板题 sol:AC自动机,还是要解决跳fail边产生的重复访问,但 ...
- [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)
题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...
- 洛谷P1393 动态逆序对(CDQ分治)
传送门 题解 听别人说这是洛谷用户的双倍经验啊……然而根本没有感觉到……因为另外的那题我是用树状数组套主席树做的……而且莫名其妙感觉那种方法思路更清晰(虽然码量稍稍大了那么一点点)……感谢Candy大 ...
- Bzoj2152/洛谷P2634 聪聪可可(点分治)
题面 Bzoj 洛谷 题解 点分治套路走一波,考虑\(calc\)函数怎么写,存一下每条路径在\(\%3\)意义下的路径总数,假设为\(tot[i]\)即\(\equiv i(mod\ 3)\),这时 ...
- 洛谷 P6199 - [EER1]河童重工(点分治+虚树)
洛谷题面传送门 神仙题. 首先看到这样两棵树的题目,我们肯定会往动态树分治的方向考虑.考虑每次找出 \(T_2\) 的重心进行点分治.然后考虑跨过分治中心的点对之间的连边情况.由于连边边权与两棵树都有 ...
- 洛谷P3966 [TJOI2013]单词(AC自动机)
题目描述 小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次. 输入输出格式 输入格式: 第一行一个整数N,表 ...
- 洛谷P2444 病毒【AC自动机】
题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否 ...
随机推荐
- pinpoint本地开发-web模块
web模块中的前端依赖会导致工程很难打包成功,对于这些,我们可以直接注释掉 比如: <plugin> <groupId>com.github.eirslett</grou ...
- SDUT 2133 数据结构实验之栈三:后缀式求值
数据结构实验之栈三:后缀式求值 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 对于一个基于二元运算符的后缀表示式(基本操作数都是 ...
- javscript 一些常用的工具方法
一些工作中经常会用到的js代码,可以封装成一个工具库. 积少成多,从现在开始吧! -------------- 1 . 判断一段文字的长度.要求中文相当于2个字符,非中文的相当于1个字符 String ...
- BZOJ 1677 [Usaco2005 Jan]Sumsets 求和:dp 无限背包 / 递推【2的幂次方之和】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1677 题意: 给定n(n <= 10^6),将n分解为2的幂次方之和,问你有多少种方 ...
- javascript(5)
(1)数组的细节: 基本用法 var 数组名=[元素值,元素值...]; 元素的值可以是任意类型. 数组是引用类型. js里的引用. 在函数参数列表中,如果传入的是基本类型,那 按值传递.如果传入的是 ...
- jquery新添加元素无法删除
$("body").on('click',".delic",function(){ $(this).parent().remove(); })
- 机器学习 Regularization and model selection
Regularization and model selection 假设我们为了一个学习问题尝试从几个模型中选择一个合适的模型.例如,我们可能用一个多项式回归模型hθ(x)=g(θ0+θ1x+θ2x ...
- shell命令自动分区提示
echo ’n p 1 +20M w’ | fdisk /dev/sda
- ACM学习历程—SNNUOJ 1110 传输网络((并查集 && 离线) || (线段树 && 时间戳))(2015陕西省大学生程序设计竞赛D题)
Description Byteland国家的网络单向传输系统可以被看成是以首都 Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的 ...
- Ubuntu环境下对拍
何为对拍 假设我在考场上写了一个能过样例的算法.然后它也能过大样例但是我觉得有些担心某些细节会出错,或者是它连大样例都过不了但是大样例过大无法肉眼差错,这个时候我们就需要对拍了. 所谓对拍,就是对着拍 ...