洛谷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自动机】
题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否 ...
随机推荐
- 20145239杜文超 《Java程序设计》第10周学习总结
20145239 <Java程序设计>第10周学习总结 教材学习内容总结 Java的网络编程 网络编程 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据. 网络概述 1.计算机 ...
- css(3)
行内元素和块内元素可以通过定义display的属性值进行相互转换. 想要叫ul中的li实现横向显示可以在li中加入布局"float:left": 如: /*这个用于控制单个图片区域 ...
- linux应用之yum命令
yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器.基於RPM包管理,能够从指定的服务器自动下载RP ...
- [原创]java在线打开PDF文档
步骤一:(涉及到的工具) 访问:http://www.zhuozhengsoft.com/dowm/,从官网下载PageOffice for Java. 步骤二:(配置工程) 1. 解压PageOff ...
- Unity-2017.3官方实例教程Space-Shooter(二)
由于初学Unity,写下此文作为笔记,文中难免会有疏漏,不当之处还望指正. Unity-2017.3官方实例教程Space-Shooter(一) 章节列表: 一.创建小行星Prefab 二.创建敌机和 ...
- BZOJ3110:[ZJOI2013]K大数查询
浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html 题目传送门:https://www.lydsy.com/JudgeOnline/prob ...
- BZOJ1382:[Baltic2001]Mars Maps
浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html 题目传送门:https://www.lydsy.com/JudgeOnline/prob ...
- BZOJ2028:[SHOI2009]会场预约(线段树版)
浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html 题目传送门:https://www.lydsy.com/JudgeOnline/prob ...
- Windows WMIC命令使用详解1
https://blog.csdn.net/enweitech/article/details/51982114 在CMD和Powershell中 使用WMIC 先决条件: a. 启动Windows ...
- deprecated conversion from string constant to ‘char*’
deprecated conversion from string constant to ‘char*’ #include <iostream> using namespace std; ...