BZOJ 1921: [Ctsc2010]珠宝商 点分治套SAM
题目链接
首先可以发现两种算法
一. 暴力处理
对"特征串"建SAM
枚举路径的一个端点,\(dfs\)另一个端点,同时维护在SAM上的位置.
每到一个位置会有SAM上对应节点的right集合大小的贡献
复杂度\(O(size^2)\)
二. 处理经过一个点的所有路径
设这个点是\(u\),字符为\(a[u]\)
需要建出正反特征串的后缀树
考虑从点\(u\)出发的所有路径(\(a[u]\)为字符串的开头),统计出以特征串的每一位为起始的这些串的数量
同理将这些串\(reverse\)(\(a[u]\)为串的最后一位),统计出在特征串每一位结束的串的数量
对应位上两组串数量的乘积的和即为贡献,因为某正串在一位起始,某反串在这位结束,即可拼出一个路径
由于\(dfs\)时正串是每次在末尾加字符维护在特征串中起始位置,反串是每次开头加字符维护结束位置,将特征串和路径串翻转后即为同一个问题,我们只考虑\(push\ front\)维护结束位置
后缀自动机的转移只能支持末尾插入,于是需要利用后缀树
后缀树上一条边会对应原串中的一段区间
转移时需要注意从上往下走了不满一条边的情况,此时大概需要走到儿子处,注意判无转移时无解
每次在节点上打标记,最后全部下放到叶子处 统计每个位置的出现次数
复杂度\(O(size+m)\)
然后使用点分治,若分治的大小\(size>\sqrt{m}\)使用方法2, 否则暴力做方法1
这里需要注意同一子树的去重 在去重的时候应使用对应的方法保证复杂度
易知复杂度为\(O((n+m)\sqrt{m})\)
代码如下
#include<cstdio>
#include<algorithm>
#include<ctype.h>
#include<string.h>
#include<math.h>using namespace std;
#define ll long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define travel(i,x) for(int i=h[x];i;i=pre[i])inline char read() {static const int IN_LEN = 1000000;static char buf[IN_LEN], *s, *t;return (s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin), (s == t ? -1 : *s++) : *s++);
}
template<class T>
inline void read(T &x) {static bool iosig;static char c;for (iosig = false, c = read(); !isdigit(c); c = read()) {if (c == '-') iosig = true;if (c == -1) return;}for (x = 0; isdigit(c); c = read()) x = ((x + (x << 2)) << 1) + (c ^ '0');if (iosig) x = -x;
}
const int OUT_LEN = 10000000;
char obuf[OUT_LEN], *ooh = obuf;
inline void print(char c) {if (ooh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), ooh = obuf;*ooh++ = c;
}
template<class T>
inline void print(T x) {static int buf[30], cnt;if (x == 0) print('0');else {if (x < 0) print('-'), x = -x;for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;while (cnt) print((char)buf[cnt--]);}
}
inline void flush() { fwrite(obuf, 1, ooh - obuf, stdout); }
const int N = 50005;
int n, m, num, tot1[N], tot2[N], h[N], pre[N<<1], e[N<<1];
bool vis[N];
char a[N], s[N];
inline void add(int x, int y){ e[++num]=y, pre[num]=h[x], h[x]=num;}
struct sam{int last, cnt, b[N], str[N], t[N<<1], lazy[N<<1], q[N<<1], siz[N<<1], len[N<<1], fa[N<<1], ch[N<<1][26], son[N<<1][26];bool isl[N<<1];inline sam(){ last=cnt=1;}inline void ins(int c){int p=last, np=++cnt;last=np, str[len[np]=len[p]+1]=c, t[np]=len[np];while(p && !ch[p][c]) ch[p][c]=np, p=fa[p];if(!p) fa[np]=1;else{int q=ch[p][c];if(len[q]==len[p]+1) fa[np]=q;else{int nq=++cnt;len[nq]=len[p]+1, memcpy(ch[nq], ch[q], sizeof ch[0]);t[nq]=t[q], fa[nq]=fa[q], fa[q]=fa[np]=nq;while(ch[p][c]==q) ch[p][c]=nq, p=fa[p];}}siz[np]=isl[np]=1;}inline void init(){rep(i, 1, cnt) ++b[len[i]];rep(i, 1, m) b[i]+=b[i-1];rep(i, 1, cnt) q[b[len[i]]--]=i;for(int i=cnt; i>1; --i) son[fa[q[i]]][str[t[q[i]]-len[fa[q[i]]]]]=q[i], siz[fa[q[i]]]+=siz[q[i]];}inline void trans(int &p, int c){ p=ch[p][c];}void dfs5(int u, int fa, int p, int l){if(!p) return;if(l==len[p]) p=son[p][a[u]];else if(str[t[p]-l]!=a[u]) p=0;if(!p) return;++lazy[p];travel(i, u) if(e[i]!=fa && !vis[e[i]]) dfs5(e[i], u, p, l+1);}inline void work(int *tot){rep(i, 2, cnt) lazy[q[i]]+=lazy[fa[q[i]]];rep(i, 1, cnt) if(isl[i]) tot[len[i]]=lazy[i];memset(lazy, 0, sizeof lazy);}
}sam1, sam2;
ll ans;
int root, ctr, Siz, mn, top, lim, siz[N], stk[N];
void dfs1(int u, int fa=0){siz[u]=1;int mx=0;travel(i, u) if(!vis[e[i]] && e[i]!=fa) dfs1(e[i], u), siz[u]+=siz[e[i]], mx=max(mx, siz[e[i]]);mx=max(mx, Siz-siz[u]);if(mx<mn) mn=mx, ctr=u;
}
inline int getctr(int u, int size){ return Siz=mn=size, dfs1(u), ctr;}
void dfs3(int u, int p, int W, int fa=0){sam1.trans(p, a[u]);if(p){ans+=W*sam1.siz[p];travel(i, u) if(!vis[e[i]] && e[i]!=fa) dfs3(e[i], p, W, u);}
}
void dfs2(int u, int fa=0){stk[++top]=a[u];int p=1;for(int i=top; i; --i) sam1.trans(p, stk[i]);dfs3(root, p, -1);travel(i, u) if(e[i]!=fa && !vis[e[i]]) dfs2(e[i], u);--top;
}
void dfs4(int u, int fa=0){dfs3(u, 1, 1);travel(i, u) if(!vis[e[i]] && e[i]!=fa) dfs4(e[i], u);
}
void solve(int u, int fa=0, int v=0){int size=Siz;if(size<=lim){if(fa){stk[top=1]=a[fa];root=v, dfs2(v);}dfs4(u);}else{if(fa){sam1.dfs5(v, fa, sam1.son[1][a[fa]], 1), sam2.dfs5(v, fa, sam2.son[1][a[fa]], 1);sam1.work(tot1), sam2.work(tot2);rep(i, 1, m) ans-=tot1[i]*tot2[m-i+1];}sam1.dfs5(u, 0, 1, 0), sam2.dfs5(u, 0, 1, 0);sam1.work(tot1), sam2.work(tot2);rep(i, 1, m) ans+=tot1[i]*tot2[m-i+1];vis[u]=1;travel(i, u) if(!vis[e[i]]) solve(getctr(e[i], siz[e[i]]<siz[u]?siz[e[i]]:size-siz[u]), u, e[i]);}
}
int main() {read(n), read(m);lim=sqrt(m);rep(i, 2, n){static int x, y;read(x), read(y);add(x, y), add(y, x);}while(isspace(a[1]=read()));rep(i, 2, n) a[i]=read();rep(i, 1, n) a[i]-='a';while(isspace(s[1]=read()));rep(i, 2, m) s[i]=read();rep(i, 1, m) sam1.ins(s[i]-='a');for(int i=m; i; --i) sam2.ins(s[i]);sam1.init(), sam2.init();solve(getctr(1, n));return printf("%lld", ans), 0;
}
转载于:https://www.cnblogs.com/CMXRYNP/p/9392692.html
BZOJ 1921: [Ctsc2010]珠宝商 点分治套SAM相关推荐
- bzoj 1921: [Ctsc2010]珠宝商
题意: 给一棵树,每个点上有一个字母,问对于所有(x,y),求x到y的路径所组成的字符串在S中出现次数的和. 题解: 先上题解:begined CTSC2010 珠宝商新解 然后说说个人的垃圾理解. ...
- bzoj 1921: [Ctsc2010]珠宝商 后缀自动机+点分治
题意 有一棵n个节点的树和一个长度为m的字符串S,树上每个节点有一个字符.问对于任意的有序数对(x,y),从x到y路径组成的字符串在S中出现次数的和. n,m<=50000n,m<=500 ...
- [CTSC2010]珠宝商 SAM+后缀树+点分治
[CTSC2010]珠宝商 不错的题目 看似无法做,n<=5e4,8s,根号算法? 暴力一: n^2,+SAM上找匹配点的right集合sz,失配了直接退出 暴力二: O(m) 统计过lca=x ...
- [CTSC2010]珠宝商(点分治+根号分治+后缀自动机)
[CTSC2010]珠宝商 洛谷题目传送门 简要题意 给定一颗nnn个节点的树,和一个长度为mmm的模式串SSS 树上每个节点都有一个字符 求树上所有路径的点的字符拼成的字符串在SSS中的出现次数之和 ...
- P4218 [CTSC2010]珠宝商
P4218 [CTSC2010]珠宝商 神题... 可以想到点分治,细节不写了... (学了个新姿势,sam可以在前面加字符 但是一次点分治只能做到\(O(m)\),考虑\(\sqrt n\)点分治, ...
- BZOJ.4184.shallot(线段树分治 线性基)
BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...
- [Ctsc2010]珠宝商 SAM+点分治+根号分治
Description 给定一个n个点的树,树上每个点有一个字符,再给一个长度为m的串. 两点的价值为:两点连接形成的字符串再m串中出现的次数. 询问两两点价值的和. Sample Input 3 5 ...
- bzoj1921 [CTSC2010]珠宝商 SAM+后缀树+点分治
Description 有一棵n个节点的树和一个长度为m的字符串S,树上每个节点有一个字符.问对于任意的有序数对(x,y),从x到y路径组成的字符串在S中出现次数的和. n,m≤5⋅104n,m\le ...
- BZOJ1921: [Ctsc2010]珠宝商(点分治+SAM)
传送门 题解: 点分治,如果点数≥n\ge \sqrt{n}≥n,则结合后缀树O(sze+m)O(sze+m)O(sze+m)处理出每个位置的开始,结束点并统计答案.否则从每个点开始暴力扩展路径. ...
最新文章
- ASP.NET Razor – 标记简介
- 单用户模式迁移home家目录
- hdu 2563(递推)
- 东大oj-1591 Circle of friends
- Windows Server2016+SQL Server 2016 Cluster安装及配置
- Atlassian JIRA 插件开发之一 环境搭建
- deb 中标麒麟_注意:银河麒麟和中标麒麟不是同一个操作系统
- 使用Scratch制作打弹球游戏-反弹球
- 媒体专访 | 许彬教授:我们离元宇宙Big Bang有多近?
- Android——横幅通知
- python输出到文件里
- jquery和JavaScript之间的联系和区别
- android记账本折线图_Android Studio——记账本以及图表可视化实现
- Firemonkey arm-linux-androideabi-ld.exe: previous definition here
- Uncaught TypeError: Cannot read properties of undefined (reading ‘0‘)
- c语言中sqrt函数_sqrt()函数以及C ++中的示例
- terraform登录ec2实例
- 《强化学习周刊》第23期:NeurIPS 2021强化学习的最新研究与应用
- 6w字泛型集合知识梳理总结
- Unity动画系统详解8:IK是什么?
热门文章
- 【073】我的wifi卡片-分享wifi密码一扫就好
- Flask Jinja2模板引擎,headfirstjavapdf百度云
- zotero+坚果云安装记录
- 公司估值越低越好吗?买市盈率低的股票究竟是赚是赔?python量化给你答案【附代码】| 邢不行
- 姜小白的python日记Day3 初识模块与数据运算
- linux 文本字符串过滤,Linux文本过滤与处理命令
- IOS VLC 播放器 开发 滑动快进和后退
- 微信公众号js接口安全域名的MP_verify_*.txt文件的放置路径
- Echarts y轴高度设置(宽度铺满整个父级高度)
- SAP MM库存盘点流程