参考:http://www.mamicode.com/info-detail-1949898.html (log2

   https://blog.csdn.net/geotcbrl/article/details/50907662

   https://blog.csdn.net/cdsszjj/article/details/79920308

   https://blog.csdn.net/ez_yww/article/details/77072632

trie 上后缀数组想做的是把 trie 树每个节点开始到根的字符串排好序,求出 rk[ ] 和 sa[ ] ,需要的话也可以求出 ht[ ]。

普通后缀数组比较大小是通过倍增,即 [ i , i+k-1 ] 和 [ i+k , i+2k-1 ] 这两个位置作为两个关键字得到 [ i , i+2k-1 ] 的排名。这里也一样。

在树上的话, i+k 变成 i 点往上第 k 个祖先;所以先处理好祖先的倍增数组;顺便作出 dep[ ] ;

希望把每个 2t 时刻的 rk 数组存下来,所以令 rk[ t ][ i ] 表示第 t 次比较的时候 i 的排名。

当前这次比较的时候,tp[ ] 里要存按第二关键字排好序的序列,即 tp[ i ] 表示 “ 2t-1 次祖先排名为 i 的节点是谁 ” ;这里的 “排名为 i ” 指的是 “向上 2t-1 范围的字符串” 排名,即 rk[ t-1 ][ i ] 。

所以现在已知上一次的 sa 和 rk ,希望做出 tp[ ] 。只要记录一下每个点的 2t-1 次后代有些谁(注意可能有多个点),然后像平常一样把没有 2t-1 次祖先的点填在最前面,再按 sa 枚举,tp[ ++tot ] = 后代 即可。

原来用 vector 存了这些后代。但非常慢。每次通过 pre[ i ][ t-1 ] 连一个临接表出来会快很多。

然后希望作出 ht 。先要作出 ht[ i ][ 0 ] 。

现在真实的排名是最后一次做出的那个 rk 。所以 ht 是基于最后一次的 rk 和 sa 上求的。保留之前的 rk 可以用来求相邻两个字符串的 LCP 。就是像倍增一样。如果 rk[ t ][ x ] == rk[ t ][ y ] ,说明 i 和 j 向上 2t 个字符都是一样的,那么 ret+= bin[ t ] , x = pre[ x ][ t ] , y = pre[ y ][ t ] 。

当然也可以不保留这些 rk ,倍增地存一下每个点往上的哈希值也行。(所以比较两个串的复杂度是 log 而不是 log2 的!“二分” 和 “提取哈希值” 可以一起做!)

(这样有一个做法,就是启发式合并,合并子树的时候把小的部分的字符串二分地插入大的部分的字符串集合中。但支持 “提取某位置的元素” 和 “插入” 的数据结构会带 log ,所以是 log3 ,真遗憾)

注意桶要包含 0 位置。因为根向上没有字符,初始 rk 是 0 。同时注意输入的边上字符有 0 ,所以把输入都 +1 ,体现 “没有” 比 0 大。

然后这道题再套一个线段树合并就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define ll long long
using namespace std;
int rdn()
{int ret=0;bool fx=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
const int N=2e5+5,K=18,bs=10007,md=1e9+9;
int n,dep[N],hs[N][K+5],pre[N][K],lj[N];
int sa[N],rk[N],ht[N][K+5],bin[K+5],lg[N];
int hd[N],xnt,to[N],nxt[N],rt[N],ans;
struct Node{int x;Node(int x=0):x(x) {}bool operator< (const Node &b)const{return rk[x]<rk[b.x];}
};
set<Node> st[N];
set<Node>::iterator it,it2;
int get_lcp(int u,int v)
{int ret=0;for(int t=lg[Mn(dep[u],dep[v])];t>=0;t--)//Mn not Mxif(pre[u][t]&&pre[v][t]&&hs[u][t]==hs[v][t])//if pre[][]u=pre[u][t], v=pre[v][t], ret+=bin[t];return ret;
}
bool cmp(int u,int v)
{for(int t=lg[Mn(dep[u],dep[v])];t>=0;t--)//Mnif(pre[u][t]&&pre[v][t]&&hs[u][t]==hs[v][t])//pre[][]u=pre[u][t], v=pre[v][t];return hs[u][0]<hs[v][0];
}
void get_ht()
{for(int i=2;i<=n;i++)ht[i][0]=get_lcp(sa[i-1],sa[i]);for(int t=1;t<=lg[n];t++)for(int i=1;i+bin[t]-1<=n;i++)ht[i][t]=Mn(ht[i][t-1],ht[i+bin[t-1]][t-1]);
}
int qry_ht(int u,int v)
{if(u==v)return dep[u];u=rk[u]; v=rk[v]; if(u>v)swap(u,v);u++; int d=lg[v-u+1];return Mn(ht[u][d],ht[v-bin[d]+1][d]);
}
int mrg(int &u,int v)
{int ret=0;if(st[u].size()<st[v].size())swap(u,v);for(it=st[v].begin();it!=st[v].end();it++){st[u].insert(*it);it2=st[u].find(*it);if(it2!=st[u].begin()){it2--; ret=Mx(ret,qry_ht((*it2).x,(*it).x));it2++;}it2++; if(it2==st[u].end())continue;ret=Mx(ret,qry_ht((*it2).x,(*it).x));}return ret;
}
void dfs(int cr)
{rt[cr]=cr; st[rt[cr]].insert(Node(cr));int ret=0;for(int i=hd[cr],v;i;i=nxt[i]){dfs(v=to[i]);ret=Mx(ret,mrg(rt[cr],rt[v]));}if(st[rt[cr]].size()>1)//if!!!
    {ans=Mx(ans,dep[cr]+ret);}
}
int main()
{freopen("recollection.in","r",stdin);freopen("recollection.out","w",stdout);n=rdn();bin[0]=1;for(int i=1;i<=K;i++)bin[i]=bin[i-1]<<1;for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;lj[0]=1;for(int i=1;i<=n;i++)lj[i]=(ll)lj[i-1]*bs%md;int he=0, tl=0;for(int i=2;i<=n;i++){pre[i][0]=rdn();hs[i][0]=rdn()+1;//+1 for cmp emptyto[++xnt]=i; nxt[xnt]=hd[pre[i][0]]; hd[pre[i][0]]=xnt;}for(int i=2;i<=n;i++){dep[i]=dep[pre[i][0]]+1;for(int t=1,d=pre[i][0];(d=pre[i][t-1]);t++){pre[i][t]=pre[d][t-1];hs[i][t]=((ll)hs[i][t-1]*lj[bin[t-1]]+hs[d][t-1])%md;}}for(int i=1;i<=n;i++)sa[i]=i; sort(sa+1,sa+n+1,cmp);for(int i=1;i<=n;i++)rk[sa[i]]=i;get_ht(); dfs(1);printf("%d\n",ans);return 0;
}

log^2

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ls Ls[cr]
#define rs Rs[cr]
#define pb push_back
using namespace std;
int rdn()
{int ret=0;bool fx=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
const int N=2e5+5,K=20,M=N*K;
int n,dep[N],pre[N][K],hd[N],xnt,to[N],nxt[N];
int ht[K][N],rk[K][N],sa[N],tp[N],tx[N],lm,ans;
int bin[K],lg[N],rt[N],Ls[M],Rs[M],fr[M],sc[M],sm[M],tot;
int h2[N],xt2,t2[N],nt2[N];
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void ad2(int x,int y){t2[++xt2]=y;nt2[xt2]=h2[x];h2[x]=xt2;}
void Rsort(int n,int nm,int t)
{for(int i=0;i<=nm;i++)tx[i]=0;// 0 !!!! for emptyfor(int i=1;i<=n;i++)tx[rk[t][i]]++;for(int i=1;i<=nm;i++)tx[i]+=tx[i-1];for(int i=n;i;i--)sa[tx[rk[t][tp[i]]]--]=tp[i];
}
void get_sa(int n,int nm)
{for(int i=1;i<=n;i++)tp[i]=i;Rsort(n,nm,0);for(int t=1;;t++){xt2=0; memset(h2,0,sizeof h2);for(int i=1;i<=n;i++)if(pre[i][t-1])ad2(pre[i][t-1],i);int tot=0;for(int i=1;i<=n;i++)if(!pre[i][t-1])tp[++tot]=i;for(int i=1;i<=n;i++)for(int j=h2[sa[i]];j;j=nt2[j])tp[++tot]=t2[j];Rsort(n,nm,t-1); rk[t][sa[1]]=nm=1;for(int i=2;i<=n;i++){int cr=sa[i], u=pre[cr][t-1], v=pre[sa[i-1]][t-1];rk[t][cr]=(rk[t-1][cr]==rk[t-1][sa[i-1]]&&rk[t-1][u]==rk[t-1][v])?nm:++nm;}lm=t; if(nm==n)break;}
}
int get_lcp(int u,int v)
{int ret=0;for(int t=lm;t>=0;t--)//t=lm!!if(pre[u][t]&&pre[v][t]&&rk[t][u]==rk[t][v])//preu=pre[u][t], v=pre[v][t], ret+=bin[t];return ret;
}
void get_ht()
{for(int i=2;i<=n;i++)ht[0][i]=get_lcp(sa[i-1],sa[i]);for(int t=1;t<=lg[n];t++)for(int i=1;i<=n;i++)ht[t][i]=Mn(ht[t-1][i],ht[t-1][i+bin[t-1]]);
}
int qry_ht(int l,int r)
{if(l==r)return dep[sa[l]];if(l>r)swap(l,r); l++; int d=lg[r-l+1];int ret=Mn(ht[d][l],ht[d][r-bin[d]+1]);return ret;
}
void build(int l,int r,int &cr,int p)
{cr=++tot; fr[cr]=sc[cr]=p;if(l==r)return; int mid=l+r>>1;if(p<=mid)build(l,mid,ls,p);else build(mid+1,r,rs,p);
}
void mrg(int l,int r,int &cr,int pr)
{if(!cr){cr=pr;return;} if(!pr)return;int mid=l+r>>1;mrg(l,mid,ls,Ls[pr]); mrg(mid+1,r,rs,Rs[pr]);fr[cr]=(ls?fr[ls]:fr[rs]); sc[cr]=(rs?sc[rs]:sc[ls]);sm[cr]=Mx(sm[ls],sm[rs]);if(fr[ls]&&fr[rs])sm[cr]=Mx(sm[cr],qry_ht(sc[ls],fr[rs]));
}
void dfs(int cr)
{build(1,n,rt[cr],rk[lm][cr]);for(int i=hd[cr],v;i;i=nxt[i]){dfs(v=to[i]);mrg(1,n,rt[cr],rt[v]);}if(hd[cr]){ans=Mx(ans,dep[cr]+sm[rt[cr]]);}
}
int main()
{freopen("recollection.in","r",stdin);freopen("recollection.out","w",stdout);n=rdn();for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;bin[0]=1;for(int i=1;bin[i-1]<=n;i++)bin[i]=bin[i-1]<<1;for(int i=2;i<=n;i++){int fa=rdn(); rk[0][i]=rdn()+1;//+1!!!!! for cmp with emptydep[i]=dep[fa]+1; pre[i][0]=fa; add(fa,i);for(int t=1,d=fa;(d=pre[i][t-1]);t++)pre[i][t]=pre[d][t-1];}get_sa(n,301); get_ht();dfs(1);printf("%d\n",ans);return 0;
}

log

转载于:https://www.cnblogs.com/Narh/p/10691259.html

2019.4.11 一题 XSY 1551 ——广义后缀数组(trie上后缀数组)相关推荐

  1. 网易2019实习生招聘编程题集合

    前言 利用周末时间做了这套网易2019实习生招聘编程题,链接如下: 题目链接 成绩 先来看一下博主的成绩,打了67分,完全做对了4道题,另外的4道题中1道题完成了80%,1道题完成了30%.评价一下就 ...

  2. 2016新疆教师计算机等级考试,2019年11月7日的新疆中小学教师计算机等级..._教师资格考试_帮考网...

    cengbiben 高能答主 07-08 TA获得超过5341个赞 内容 : 关于2019年11月高校计算机等级考试报名的通知各学院,各班级学生: 接省教育厅通知,2019年11月7日将举行浙江省高校 ...

  3. 湖湘杯2019两个密码题wp

    湖湘杯2019两个密码题wp   还是自己太菜的原因,这次湖湘杯只做出来4道题,然后5点的时候就放弃了去跟同学出去玩了,当时感觉进前50无望(这次湖湘杯py情况也很严重啊,可惜烽火台只报不封,挺恶心的 ...

  4. 2019年11月计算机考试,重庆信息技术职业学院--[考试中心]关于2019年11月全国信息化计算机应用技术水平认证考试CCAT(1905期)报名的通知...

    关于2019年11月全国信息化计算机应用技术水平认证考试 CCAT(1905期)报名的通知 各二级学院.处(室)以及各位考生: 根据学院安排,并报重庆考试中心批准,暂定于2019年11月30日在我院举 ...

  5. Visual Studio 2022 Preview 3和2019 16.11发布

    Visual Studio 2022 Preview 3 主要特点 个人和团队生产力 附加到进程改进 新项目设计器 黑暗主题提升 开发现代应用 远程测试 新的JavaScript和TypeScript ...

  6. VS 2019 16.11正式发布 | 新功能(Hot Reload 热重载)试用

    VS 2019 16.11 VS 2019 16.11已于2021.8.10正式发布.(https://devblogs.microsoft.com/visualstudio/visual-studi ...

  7. 2019双11,支付宝有哪些“秘密武器”?

    2019双11,支付宝参战的第十一年. 与十一年前相比,双11的许多东西都改变了.比如金额--2684亿,差不多是十一年前的5000倍:比如流量--订单峰值54.4万笔/秒,曾经是想都不敢想的数字:再 ...

  8. 揭秘2019双11背后的云网络 – 双11网络架构和洛神系统

    图1 天猫双11成交额 2019年天猫双11成交额,2684亿!核心系统100%上云!全球最大流量洪峰,阿里云扛住了.  狂欢背后的技术栈 网上轻松购物体验实际上是背后复杂的技术组成的,这是一个简化 ...

  9. 2019年11月数据库流行度排行:前三甲大幅下跌 PM 应云而升 国产续领风云

    2019年11月数据库流行度排行出炉,在积分榜单上,前 3 位的 Oracle.MySQL 和 Microsoft SQL Server 环比都出现了大幅下跌,其中 Oracle 数据库下跌 19.8 ...

最新文章

  1. 给初学者的深度学习入门指南
  2. tcp时间戳 引起的网站不能访问
  3. python TypeError: Expected int32, got list containing Tensors of type '_Message' instead.
  4. 【Linux】一步一步学Linux——domainname命令(172)
  5. android pay 绑定失败,实战Apple Pay失败!Android Pay你期待吗?
  6. jquery验证手机号码和邮箱地址例子
  7. AccuREST Stub Runner发布
  8. 2020-10-22
  9. 固定资产管理系统项目总结
  10. 教你利用腾讯云cdn加速网站静态资源
  11. matlab 图像上加边框,matlab代码-图像上画框 | 学步园
  12. pycharm占用c盘
  13. 进击的DApp:区块链上将长出怎么样的新事物?
  14. canvas实现漂亮的下雨效果
  15. 非递归式查找树形数据
  16. python桌面爬虫_爬虫项目实战十三:爬取zol桌面壁纸
  17. html语言中kbd的含义,HTML: kbd 标签
  18. android平台opengl es读取纹理数据并保存图片
  19. 销 售 具 备 10 条
  20. C/C++图形库EasyX使用

热门文章

  1. 有没有便宜的易优cms授权(易优cms授权便宜获取)
  2. 【FinE】CAPM和Carhart四因子模型实证
  3. 英伟达 linux 官方驱动 双显卡,反复几次:今天终于弄好双显卡驱动了!
  4. CSS 幻术 | 有关光影效果的黑魔法
  5. 列表标签,表格标签,表单标签
  6. electron+vue3全家桶+vite项目搭建【九】集成vite-plugin-mock-server 模拟后端请求
  7. 小黑重装WIFI之解 - 硬件无线电已关闭 802.11无线通信 禁用状态无法启用
  8. torch01:torch基础
  9. 【Dr.爱疯限时免费软体报报】 2014年06月9号 iPhone、iPad、iOS APP
  10. 数学分形之谢尔宾方毯