国际惯例的题面:

考虑我们求解出字符串uvu第一个u的右端点为i,第二个u的右端点为j,我们需要满足什么性质?
显然j>i+L,因为我们选择的串不能是空串。
另外考虑i和j的最长公共前缀(也就是说其parent树上lca的len),为了保证他们相同,我们需要:
j-len>=i-L。
整理一下,如果我们已知i,j需要在区间[i+L+1,i+L+len]中。
如果我们已知j,i需要在区间[j-L-len,j-L-1]中。
于是我们可以写n^2暴力了:暴力维护parent上每个节点的right集合,对于每个i,暴力向上跳,暴力找可行的j。
然后我们发现,维护right集合可以用主席树启发式合并做,对于计算贡献,我们可以先枚举lca,然后计算有多少组可行的i,j。
在第二个计算的时候,我们显然是会在两颗主席树进行合并的时候进行计算,于是我们可以把较小的那颗拍扁,在另外一棵里暴力查询每一个值的贡献。
这样总复杂度O(nlog^2n),轻松AC。
注意主席树启发式合并的时间和空间复杂度都是O(nlog^n)的,因为考虑每层摊还下来只会被新建logn次(我已经把长度和节点个数乘起来了)。
另外这题字符集大小为全体可见字符,所以需要用map存后缀自动机。
(不是很明白为什么网上那么多题解都是后缀数组的,明明后缀自动机这么好写(不会后缀数组的就不要说话了.jpg))

代码:

 #include<cstdio>
#include<cstring>
#include<map>
#include<queue>
using namespace std;
const int maxn=1e5+1e2,maxl=; char in[maxn>>];
int li,lim;
int seq[maxn>>],seqlen;
long long ans; struct PersistentSegmentTree {
int lson[maxn*maxl<<],rson[maxn*maxl<<],siz[maxn*maxl<<],cnt;
inline void insert(int &pos,int l,int r,int tar) {
if( !pos ) pos = ++cnt; siz[pos] = ;
if( l == r ) return;
const int mid = ( l + r ) >> ;
if( tar <= mid ) insert(lson[pos],l,mid,tar);
else insert(rson[pos],mid+,r,tar);
}
inline int merge(int p1,int p2,int l,int r) {
if( ! ( siz[p1] && siz[p2] ) ) return siz[p1] ? p1 : p2;
int ret = ++cnt; siz[ret] = siz[p1] + siz[p2];
if( l == r ) return ret;
const int mid = ( l + r ) >> ;
lson[ret] = merge(lson[p1],lson[p2],l,mid) ,
rson[ret] = merge(rson[p1],rson[p2],mid+,r) ;
return ret;
}
inline int query(int pos,int l,int r,const int &ll,const int &rr) {
if( !pos ) return ;
if( ll <= l && r <= rr ) return siz[pos];
const int mid = ( l + r ) >> ;
if( rr <= mid ) return query(lson[pos],l,mid,ll,rr);
else if( ll > mid ) return query(rson[pos],mid+,r,ll,rr);
return query(lson[pos],l,mid,ll,rr) + query(rson[pos],mid+,r,ll,rr);
}
inline void dfs(int pos,int l,int r) {
if( !pos ) return;
if( l == r ) return void(seq[++seqlen]=l);
const int mid = ( l + r ) >> ;
dfs(lson[pos],l,mid) , dfs(rson[pos],mid+,r);
}
inline int getsiz(int pos) {
return siz[pos];
}
}segt; namespace SAM {
int fa[maxn],len[maxn],deg[maxn],last,root,cnt;
int rit[maxn],roots[maxn];
map<int,int> ch[maxn];
inline int NewNode(int ll) {
len[++cnt] = ll;
return cnt;
}
inline int extend(int x,int rr) {
int p = last;
int np = NewNode(len[p]+); rit[np] = rr;
while( ch[p].find(x) == ch[p].end() ) ch[p][x] = np , p = fa[p];
if( !p ) fa[np] = root;
else {
int q = ch[p][x];
if( len[q] == len[p] + ) fa[np] = q;
else {
int nq = NewNode(len[p]+);
ch[nq] = ch[q] , fa[nq] = fa[q];
fa[np] = fa[q] = nq;
while( p && ch[p][x] == q ) ch[p][x] = nq , p = fa[p];
}
}
return last = np;
}
inline int query(int root,int i,int samelen) {
if( samelen < ) return ;
int ret = segt.query(root,,li,i+lim+,i+lim+samelen);
if( i - lim - > ) ret += segt.query(root,,li,i-lim-samelen,i-lim-);
return ret;
}
inline void topo() {
for(int i=;i<=cnt;i++) if( fa[i] ) ++deg[fa[i]];
queue<int> q;
for(int i=;i<=cnt;i++) if( !deg[i] ) q.push(i);
while( q.size() ) {
const int pos = q.front(); q.pop();
if( pos == root ) continue;
if( rit[pos] ) {
ans += query(roots[pos],rit[pos],len[pos]);
int t = ; segt.insert(t,,li,rit[pos]);
roots[pos] = segt.merge(roots[pos],t,,li);
}
if( segt.getsiz(roots[fa[pos]]) < segt.getsiz(roots[pos]) ) // We won't use roots[pos] again .
swap(roots[fa[pos]],roots[pos]);
seqlen = , segt.dfs(roots[pos],,li);
for(int i=;i<=seqlen;i++) ans += query(roots[fa[pos]],seq[i],len[fa[pos]]);
roots[fa[pos]] = segt.merge(roots[fa[pos]],roots[pos],,li);
if( !--deg[fa[pos]] ) q.push(fa[pos]);
}
}
} int main() {
scanf("%d%s",&lim,in+) , li = strlen(in+);
SAM::last = SAM::root = SAM::NewNode();
for(int i=;i<=li;i++) SAM::extend(in[i],i);
SAM::topo();
printf("%lld\n",ans);
return ;
}

Bzoj2534:后缀自动机 主席树启发式合并的更多相关文章

  1. UVA - 10829 L-Gap Substrings (后缀自动机+线段树启发式合并)

    题意:统计一段字符串中形如UVU的子串个数(其中V的长度固定为g). 问题等价于求满足$g+1\leqslant |j-i|\leqslant g+LCP(i,j)$的后缀(i,j)的对数,即$\su ...

  2. P3302 [SDOI2013]森林(主席树+启发式合并)

    P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...

  3. 【BZOJ-3123】森林 主席树 + 启发式合并

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2738  Solved: 806[Submit][Status] ...

  4. [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT

    Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...

  5. 【主席树 启发式合并】bzoj3123: [Sdoi2013]森林

    小细节磕磕碰碰浪费了半个多小时的时间 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M ...

  6. BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并

    BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20 ...

  7. 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并

    题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...

  8. Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)

    3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...

  9. BZOJ5137&&lg4081(广义后缀自动机,set启发式合并)

    BZOJ5137&&lg4081(广义后缀自动机,set启发式合并) 题面 自己找去 HINT 给定多个文本串,让你查询每个文本串中有多少个本质不同的子串且这个子串只出现在当前这个文本 ...

随机推荐

  1. windows10 升级1803后,远程错误提示“出现身份验证错误,要求的函数不受支持 CredSSP 加密 Oracle修正”的解决办法

    远程出现错误提示:出现身份验证错误,要求的函数不受支持 CredSSP 加密 Oracle修正 运行 gpedit.msc 本地组策略: 计算机配置>管理模板>系统>凭据分配> ...

  2. UVALive 2218 Triathlon

    https://vjudge.net/problem/UVALive-2218 题意: 铁人三项比赛,每项比赛长度未定,已知每个选手每项比赛的平均速度. 设计每项比赛的长度,让其中某个特定选手获胜. ...

  3. info replication

    主Redis设置值:redis-cli -h 192.168.18.121 -p 63800 -a tinywan123456 登陆从1:redis-cli -h 192.168.18.121 -p ...

  4. git 学习小记

    话说 git 出了已经很久了,可是我一直没用过.其实也不是没用过,只不过在 github 上下载东西那根本就不是在用 git,只是单纯的HTTP下载而已.我们公司用的是 svn,所以我只会一点点svn ...

  5. js调试系列: 调试基础与技巧

    js调试系列目录: - 昨天我们见识到了断点的强悍,在断点的配合下进行动态调试,让读代码变的轻松不少,特别是ajax之类的.在昨天的课后练习中,确实增加了不少难度,因为 提交评论 按钮是用 jQuer ...

  6. [原]Android开发优化-Adapter优化

    ListView作为Android开发中使用频率最高的一个控件,保证ListView的流畅运行,对用户体验的提高至关重要.Adapter是ListView和数据源之间的中间人,当每条数据进入可见区时, ...

  7. 20155314 2016-2017-2 《Java程序设计》第6周学习总结

    20155314 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 理解流与IO 理解InputStream/OutPutStream的继承架构 理解Reade ...

  8. 关于gb2312编码和utf8码的一个问题

    ANSI(注意拼写不是ASCII)并不是“一种”编码,而是“多种”编码的统称.在简体中文Windows上,ANSI指GBK编码:在繁体中文Windows上,ANSI指Big5编码:在英文Windows ...

  9. aliyun EC2配置利用filezilla配置ftp服务

    项目需要在阿里云EC2虚拟主机上配置ftp服务器,看了阿里云的教程可以使用filezilla配置,但一直遇到了一些问题.现记录一些步骤,避免以后出现类似问题. 1安装filezilla server ...

  10. Oracle 用脚本安装第二个数据库

    安装第二个数据库: 登录oracle用户进入家目录,添加配置环境变量: vi .bash_profier ORACLE_SID=prod2   临时环境变量: $export ORACLE_HOME= ...