SA的一个辣鸡trick
基础板子
namespace SA{
int x[400010],y[400010],SA[400010],rk[400010],ht[400010],t[400010];
int st[19][400010],lg[400010];
il int getLCP(int x,int y){
if(x==y)return 1e9;
int l=lg[y-x];
return std::min(st[l][x],st[l][y-(1<<l)]);
}
il vd getSA(){
int set=400000;
for(int i=1;i<=N;++i)++t[x[i]=S[i]];
for(int i=1;i<=set;++i)t[i]+=t[i-1];
for(int i=N;i;--i)SA[t[x[i]]--]=i;
for(int k=1;k<=N;k<<=1){
int p=0;
for(int i=N-k+1;i<=N;++i)y[++p]=i;
for(int i=1;i<=N;++i)if(SA[i]>k)y[++p]=SA[i]-k;
for(int i=1;i<=set;++i)t[i]=0;
for(int i=1;i<=N;++i)++t[x[y[i]]];
for(int i=1;i<=set;++i)t[i]+=t[i-1];
for(int i=N;i;--i)SA[t[x[y[i]]]--]=y[i];
std::swap(x,y);x[SA[1]]=p=1;
for(int i=2;i<=N;++i){
if(y[SA[i]]!=y[SA[i-1]]||y[SA[i]+k]!=y[SA[i-1]+k])++p;
x[SA[i]]=p;
}
if(p>=N)break;set=p;
}
for(int i=1;i<=N;++i)rk[SA[i]]=i;
for(int i=1,j,k;i<=N;++i){
if(rk[i]==N)continue;
if(k)--k;
j=SA[rk[i]+1];
while(S[i+k]==S[j+k])++k;
ht[rk[i]]=k;
}
for(int i=2;i<=N;++i)lg[i]=lg[i>>1]+1;
for(int i=1;i<=N;++i)st[0][i]=ht[i];
for(int i=1;i<=lg[N];++i)
for(int j=1;j+(1<<i)-1<=N;++j)
st[i][j]=std::min(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
}
用SA给后缀排序以后,就可以处理“和一个后缀的LCP>=k的所有后缀的信息和”这样的问题了,因为和一个后缀的LCP>=k的所有后缀在SA数组上是连续的一段。
但是有一些题目并不能做,只能用sam建树,加上线段树合并做。
因为sam维护的是子树查询,而SA这个做法是区间询问,子树查询的性质当然比区间询问更好然而我不会sam
然后我发现我sb了,其实SA这个“和一个后缀的LCP>=k的所有后缀”的区间肯定只有相互包含和不交这两种关系,所以这也是一棵树= =如果建出来这个树就可以和SAM一样做了。
建树也很简单= =NOIP2018铺设道路
然后就也能够处理这样的东西了,和后缀x的LCP>=k的所有后缀直接倍增一下查询那个点,和sam差不多
#include<bits/stdc++.h>
#define il inline
#define vd void
#define ll long long
il int gi(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f^=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
char s[100010];
int n,Q;
namespace SA{
int SA[100010],rk[100010],ht[100010],Log[100010],st[17][100010];
il int LCP(int x,int y){
if(x==y)return 1e9;int l=Log[y-x];
return std::min(st[l][x],st[l][y-(1<<l)]);
}
il vd getSA(){
static int x[100010],y[100010],t[100010];
struct gety{il int operator()(int x){return x<=n?y[x]:-1;}}gety;
int set=128;
for(int i=1;i<=n;++i)++t[x[i]=s[i]];
for(int i=1;i<=set;++i)t[i]+=t[i-1];
for(int i=n;i;--i)SA[t[x[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(int i=n-k+1;i<=n;++i)y[++p]=i;
for(int i=1;i<=n;++i)if(SA[i]>k)y[++p]=SA[i]-k;
for(int i=1;i<=set;++i)t[i]=0;
for(int i=1;i<=n;++i)++t[x[y[i]]];
for(int i=1;i<=set;++i)t[i]+=t[i-1];
for(int i=n;i;--i)SA[t[x[y[i]]]--]=y[i];
std::swap(x,y);x[SA[1]]=p=1;
for(int i=2;i<=n;++i){
if(gety(SA[i])!=gety(SA[i-1])||gety(SA[i]+k)!=gety(SA[i-1]+k))++p;
x[SA[i]]=p;
}
if(p==n)break;set=p;
}
for(int i=2;i<=n;++i)Log[i]=Log[i>>1]+1;
for(int i=1;i<=n;++i)rk[SA[i]]=i;
for(int i=1,j,k=0;i<=n;++i){
if(rk[i]==n)continue;
if(k)--k;j=SA[rk[i]+1];
while(s[i+k]==s[j+k])++k;
ht[rk[i]]=k;
}
for(int i=1;i<=n;++i)st[0][i]=ht[i];
for(int i=1;i<=Log[n];++i)
for(int j=1;j+(1<<i)-1<=n;++j)
st[i][j]=std::min(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
}
int cnt;
int fir[200010],dis[200010],nxt[200010],id;
il vd link(int a,int b){nxt[++id]=fir[a],fir[a]=id,dis[id]=b;}
int depest[200010],sL[200010],sR[200010],sP[200010];
int st[18][200010],siz[200010],son[200010];
il int buildTree(int L,int R){
int x=++cnt;sL[x]=L,sR[x]=R;siz[x]=1;
if(L==R){sP[x]=1e9;return depest[L]=x;}
int p=SA::LCP(L,R),l,r,mid;sP[x]=p;
for(int i=L;i<=R;++i){
l=i,r=R;
while(l<r){
mid=((l+r)>>1)+1;
if(SA::LCP(i,mid)>p)l=mid;
else r=mid-1;
}
int t=buildTree(i,l);st[0][t]=x;siz[x]+=siz[t];
if(siz[son[x]]<siz[t])son[x]=t;
link(x,t);
i=l;
}
return x;
}
SA的一个辣鸡trick的更多相关文章
- JVM 辣鸡回收
垃圾回收算法 标记清除法 先标记出需要回收的对象,然后一次性回收.缺点:会产生内存碎片,并且效率也不高. 标记压缩法 先标记出需要回收的对象,然后让存活对象向一端移动,移动的过程中进行回收辣鸡.避免了 ...
- [CSP-S模拟测试]:辣鸡(ljh) (暴力)
题目描述 辣鸡$ljh\ NOI$之后就退役了,然后就滚去学文化课了.然而在上化学课的时候,数学和化学都不好的$ljh$却被一道简单题难住了,受到了大佬的嘲笑.题目描述是这样的:在一个二维平面上有一层 ...
- noip模拟6[辣鸡·模板·大佬·宝藏]
这怕不是学长出的题吧 这题就很迷 这第一题吧,正解竟然是O(n2)的,我这是快气死了,考场上一直觉得aaaaa n2过不了过不了, 我就去枚举边了,然后调了两个小时,愣是没调出来,然后交了个暴力,就走 ...
- NOIP模拟测试10「大佬·辣鸡·模板」
大佬 显然假期望 我奇思妙想出了一个式子$f[i]=f[i-1]+\sum\limits_{j=1}^{j<=m} C_{k \times j}^{k}\times w[j]$ 然后一想不对得容 ...
- 7.29 NOIP模拟测试10 辣鸡(ljh)+模板(ac)+大佬(kat)
T1 辣鸡(ljh) 就是一道分类讨论的暴搜,外加一丢丢的减枝,然而我挂了,为啥呢,分类讨论变量名打错,大于小于号打反,能对才怪,写了sort为了调试就注释了,后来忘了解开,小减枝也没打.但是这道题做 ...
- qsc round#2 喵哈哈村的排队(本辣鸡想七想八的,特写此博文给自己一个提醒)
该oj是qsc自己写的比赛,友情链接:http://qscoj.cn/ 喵哈哈村的排队 发布时间: 2017年2月26日 16:13 最后更新: 2017年2月26日 16:14 时间限制: ...
- bzoj2141排队(辣鸡但是好写的方法)
题意很明确,也非常经典: 一个支持查询 区间中比k大的数的个数 并且支持单点修改的序列 ——因为题意可以转化为:查询这两个数中比后者大的个数.比后者小的个数.比前者大的个数.比前者小的个数(根据这4个 ...
- 记2017问鼎杯预赛的wp---来自一个小菜鸡的感想
这次准备写一下几个misc和密码题目..很坑. 打了一整天的比赛,越来越觉得自己很菜了. 有一道题目叫做"真真假假",这道题目只有一个提示--Xor.第一眼知道是异或,也就知道这一 ...
- Redux系列02:一个炒鸡简单的react+redux例子
前言 在<Redux系列01:从一个简单例子了解action.store.reducer>里面,我们已经对redux的核心概念做了必要的讲解.接下来,同样是通过一个简单的例子,来讲解如何将 ...
随机推荐
- Android-滑动解锁高亮文字自定义TextView
public class HightLightTextView extends TextView { // 存储view的宽度 private int mTextViewWidth = 0; // 画 ...
- PHP类多继承的替代方案Traits
概述 traits是PHP5.4新进入的特性,其目的就是解决PHP的类不能多继承的问题.Traits不是类!不能被实例化.可以理解为一组能被不同的类都能调用到的方法集合.只需要在类中使用关键词use引 ...
- [20171107]dbms_shared_pool.pin.txt
[20171107]dbms_shared_pool.pin.txt --//昨天与别人聊天提到,如果dbms_shared_pool.pin对象,可以改变对应的chunk的类型.我自己也不确定,做一 ...
- Excel函数进阶
#笔记:为了方便自己以后查找,以便随时随地能查看.形成系统化学习! 查找引用函数 ------------------包含----------Vlookup函数(if数组).Hlookup函数.loo ...
- python第二十二天-----在做作业当中............
作业 1, ATM:模拟实现一个ATM + 购物商城程序 额度 自定义实现购物商城,买东西加入 购物车,调用信用卡接口结账可以提现,手续费5%支持多账户登录支持账户间转账记录每月日常消费流水提供还款接 ...
- CentOS7安装搭建.Net Core 2.0环境-详细步骤
一.构建.Net core 2的应用程web发布 因为是用来测试centos上的core 环境,先直接用vs17自带的core实例. 二.部署CentOS7的core环境 1.连接并启动之前安装的虚拟 ...
- 30个最常用的Linux系统命令行
1.cd命令这是一个非常基本,也是大家经常需要使用的命令,它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径.如:cd /root/Docements # 切换到目录 ...
- Ubuntu 12.10 Tty (字符终端) 显示中文,和字体大小设置
Tty通过修改默认的中文编码字符,和安装zhcon都无法显示中文.可安装fbterm来显示中文,命令:sudo apt-get install fbterm安装即可,进入Tty: (Ctrl+Alt+ ...
- idea+spring-boot+devtools热部署
idea+spring-boot+devtools热部署 标签: spring-boot 2017-03-20 14:45 2635人阅读 评论(1) 收藏 举报 分类: spring-boot m ...
- WPFのImage控件souce引入的方法总结
1.后台代码相对路径添加(若为绝对路径,换UriKind的属性即可) BitmapImage testBitmapImage = new BitmapImage(new Uri(@"\bin ...