对S建SAM,拿着T在上面跑

跑的时候不仅无法转移要跳parent,转移过去不在范围内也要跳parent(注意因为范围和长度有关,跳的时候应该把长度一点一点地缩)

这样就能得到对于T的每个前缀,它最长的不合法的后缀的长度ill[i]

得到他要去重,以后可以再对T建SAM,然后对于每个节点,$ans+=max(0,len[i]-max(len[fa[i]],ill[pos[i]]))$,其中pos[i]是它的right集合中随便一个位置(因为每个位置的小于len的ill都一样)

那么怎么判在不在范围内呢..似乎可以线段树合并,带个log地求出每个节点的right

当然也可以直接dfs序然后建主席树

 #include<bits/stdc++.h>
#define pa pair<int,int>
#define CLR(a,x) memset(a,x,sizeof(a))
#define MP make_pair
using namespace std;
typedef long long ll;
const int maxn=1e6+; inline char gc(){
return getchar();
static const int maxs=<<;static char buf[maxs],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,maxs,stdin),p1==p2)?EOF:*p1++;
}
inline ll rd(){
ll x=;char c=gc();bool neg=;
while(c<''||c>''){if(c=='-') neg=;c=gc();}
while(c>=''&&c<='') x=(x<<)+(x<<)+c-'',c=gc();
return neg?(~x+):x;
} struct SAM{
int len[maxn*],fa[maxn*],tr[maxn*][],pct,lst,pos[maxn*]; inline void clear(){
while(pct){
CLR(tr[pct],);
len[pct]=fa[pct]=pos[pct]=;
pct--;
}pct=lst=;
} inline void insert(int x,bool b){
int p=++pct;
len[p]=len[lst]+;pos[p]=len[p];
int o=lst;lst=p;
for(;o&&!tr[o][x];o=fa[o]) tr[o][x]=p;
if(!o){fa[p]=;return;}
int q=tr[o][x];
if(len[q]==len[o]+){fa[p]=q;return;}
int qq=++pct;if(b) pos[qq]=pos[p];
len[qq]=len[o]+;fa[qq]=fa[q];
memcpy(tr[qq],tr[q],sizeof(tr[q]));
fa[q]=fa[p]=qq;
for(;o&&tr[o][x]==q;o=fa[o]) tr[o][x]=qq;
}
}S,T; char s[maxn];
int N,M,Q;
int ill[maxn];
int cnt[maxn],rnk[maxn],dfn[maxn][],id[maxn],tot;
vector<int> eg[maxn]; inline void dfs(int x){
id[++tot]=x;dfn[x][]=tot;
for(int i=;i<eg[x].size();i++) dfs(eg[x][i]);
dfn[x][]=tot;
} int rt[maxn],num[maxn*],ch[maxn*][],pct; inline void insert(int pre,int &p,int l,int r,int x,int y){
p=++pct;num[p]=num[pre]+y;
if(l<r){
int m=l+r>>;
if(x<=m) insert(ch[pre][],ch[p][],l,m,x,y),ch[p][]=ch[pre][];
else insert(ch[pre][],ch[p][],m+,r,x,y),ch[p][]=ch[pre][];
}
} inline int query(int pre,int p,int l,int r,int x,int y){
if(x>y) return ;
if(x<=l&&r<=y) return num[p]-num[pre];
int m=l+r>>,re=;
if(x<=m) re=query(ch[pre][],ch[p][],l,m,x,y);
if(y>=m+) re+=query(ch[pre][],ch[p][],m+,r,x,y);
return re;
} int main(){
//freopen("","r",stdin);
int i,j,k;
scanf("%s",s+);N=strlen(s+);
S.clear();
for(i=;i<=N;i++) S.insert(s[i]-'a',); for(i=;i<=S.pct;i++) eg[S.fa[i]].push_back(i);
dfs();
for(i=;i<=tot;i++){
if(S.pos[id[i]]) insert(rt[i-],rt[i],,N,S.pos[id[i]],);
else rt[i]=rt[i-];
} Q=rd();
for(i=;i<=Q;i++){
scanf("%s",s+);M=strlen(s+);
int l=rd(),r=rd();
int now=,nl=;
for(j=;j<=M;j++){
int x=s[j]-'a';
while(now&&!(S.tr[now][x]&&query(rt[dfn[S.tr[now][x]][]-],rt[dfn[S.tr[now][x]][]],,N,l+nl,r))){
if(!nl){now=;break;}
nl--;
if(nl==S.len[S.fa[now]]) now=S.fa[now];
}
if(now) nl++,now=S.tr[now][x];
else now=;
ill[j]=nl;
// printf("~%d %d\n",j,ill[j]);
}
T.clear();
for(j=;j<=M;j++) T.insert(s[j]-'a',);
ll ans=;
for(j=;j<=T.pct;j++){
ans+=max(,T.len[j]-max(T.len[T.fa[j]],ill[T.pos[j]]));
}
printf("%lld\n",ans);
}
return ;
}

最新文章

  1. 腾讯云CentOS系统配置apache和tomcat
  2. SET基本数据类型
  3. java基础学习总结——基础语法1
  4. Eclipse 反编译插件安装jad
  5. OLE填充EXCEL
  6. js为DIV动态设置id属性
  7. Orion Network Performance Monitor 软件在网络管理中的应用
  8. 使用DOM进行xml文档的crud(增删改查)操作&lt;操作详解&gt;
  9. IOS 访问系统粘贴板
  10. 泛型Binary Search Tree实现,And和STL map比较的经营业绩
  11. linux脚本Shell之九九乘法表
  12. Nginx Image Module图片缩略图 水印处理模块
  13. Lintcode389 Valid Sudoku solution 题解
  14. KMP性质小结
  15. java中==和equals的区别(转)
  16. jQueryUI使用指南
  17. centos7设置iptables
  18. Python之反射练习
  19. c# 判断文件是否已使用
  20. 【Python】安装python包时遇到&quot;error: Microsoft Visual C++ 9.0 is required&quot;的简答

热门文章

  1. MongoDB 提升性能的18原则(开发设计阶段)
  2. Python第三天 序列 5种数据类型 数值 字符串 列表 元组 字典 各种数据类型的的xx重写xx表达式
  3. webmagic 爬取网页所有文章的标题时间作者和内容
  4. Linux shell 及命令汇总
  5. MFC自绘菜单
  6. Windows server2008R2 企业内部搭建虚拟专用网络服务
  7. LeetCode算法题-Distribute Candies(Java实现)
  8. Linux文件目录
  9. 被低估的.net(上) - 微软MonkeyFest 2018广州分享会活动回顾
  10. Loj #2495. 「AHOI / HNOI2018」转盘