对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 ;
}

luogu4770 [NOI2018]你的名字 (SAM+主席树)的更多相关文章

  1. Luogu4770 NOI2018 你的名字 SAM、主席树

    传送门 UPD:发现之前被smy误导的一个细节,改过来之后就AC了-- 一道比较套路的SAM题,虽然我连套路都不会-- 先考虑前\(68pts\),也就是\(l=1 , r=|S|\)的情况.我们对\ ...

  2. [NOI2018]你的名字(SAM+线段树合并)

    考虑l=1,r=n的68分,对S和T建SAM,对T的SAM上的每个节点,计算它能给答案带来多少贡献. T上节点x代表的本质不同的子串数为mx[x]-mx[fa[x]],然后需要去掉所代表子串与S的最长 ...

  3. NOI2018 你的名字——SAM+线段树合并

    题目链接在这里洛谷/LOJ 题目大意 有一个串\(S\),每次询问给你一个串\(T\),两个数\(L\)和\(R\),问你\(T\)有多少个本质不同的子串不是\(S[L,R]\)的子串 SOLUTIO ...

  4. 【BZOJ5417】[NOI2018]你的名字(线段树,后缀自动机)

    [BZOJ5417][NOI2018]你的名字(线段树,后缀自动机) 题面 BZOJ 洛谷 题解 首先考虑\(l=1,r=|S|\)的做法,对于每次询问的\(T\)串,暴力在\(S\)串的\(SAM\ ...

  5. 【NOI2019模拟2019.6.29】字符串(SA|SAM+主席树)

    Description: 1<=n<=5e4 题解: 考虑\(f\)这个东西应该是怎样算的? 不妨建出SA,然后按height从大到小启发式合并,显然只有相邻的才可能成为最优答案.这样的只 ...

  6. luogu4770 [NOI2018]你的名字 后缀自动机 + 线段树合并

    其实很水的一道题吧.... 题意是:每次给定一个串\(T\)以及\(l, r\),询问有多少个字符串\(s\)满足,\(s\)是\(T\)的子串,但不是\(S[l .. r]\)的子串 统计\(T\) ...

  7. Luogu4770 NOI2018你的名字(后缀自动机+线段树合并)

    先考虑l=1,r=n,并且不要求本质不同的情况.对原串建SAM,将询问串在上面跑,得到每个前缀的最长匹配后缀即可得到答案. 然后考虑本质不同.对询问串也建SAM,统计每个节点的贡献,得到该点right ...

  8. Luogu4770 NOI2018你的名字(后缀数组+线段树)

    即求b串有多少个本质不同的非空子串,在a串的给定区间内未出现.即使已经8102年并且马上就9102年了,还是要高举SA伟大旗帜不动摇. 考虑离线,将所有询问串及一开始给的串加分隔符连起来,求出SA.对 ...

  9. 【NOI2018】你的名字(SAM & 线段树合并)

    Description Hint Solution 不妨先讨论一下无区间限制的做法. 首先"子串"可以理解为"前缀的后缀",因此我们定义一个 \(\lim(i) ...

随机推荐

  1. Fragment与Activity的接口回调

    这里说一个官方推荐的写法: private OnFragmentInteractionListener mListener; @Override public void onAttach(Contex ...

  2. java之网络爬虫介绍

    文章大纲 一.网络爬虫基本介绍二.java常见爬虫框架介绍三.WebCollector实战四.项目源码下载五.参考文章   一.网络爬虫基本介绍 1. 什么是网络爬虫   网络爬虫(又被称为网页蜘蛛, ...

  3. Ubuntu 18.04 安装博通(Broadcom)无线网卡驱动

    目录 Ubuntu 18.04 安装博通(Broadcom)无线网卡驱动 Package gcc is not configured yet. 解决办法 history history | grep ...

  4. Linux中DHCP服务器的简单配置

    我安装了两台linux系统,一个作为服务器,一个客户端 两个都有3个网卡, 后两个网卡聚合为zhi一个网卡:Linux 网卡聚合 两台电脑都一样. 那么如何为这个聚合网卡进行DHCP的分配呢? 1.由 ...

  5. 简说raid1 raid2 raid5 raid6 raid10的优缺点和做各自raid需要几块硬盘

    Raid 0:一块硬盘或者以上就可做raid0优势:数据读取写入最快,最大优势提高硬盘容量,比如3快80G的硬盘做raid0 可用总容量为240G.速度是一样.缺点:无冗余能力,一块硬盘损坏,数据全无 ...

  6. Java - String 的字面量、常量池、构造函数和intern()函数

    一.内存中的 String 对象 Java 的堆和栈 对于基本数据类型变量和对象的引用,也就是局部变量表属于栈内存: 而通过 new 关键字和 constructor 创建的对象存放在堆内存: 直接的 ...

  7. Server 2008 R2多用户远程桌面连接授权,解决120天过期问题

    在工作中,我们往往需要远程服务器,经常会遇到以下这两个麻烦事. 一.远程桌面的连接数限制,超出系统就会提示超过连接数. 二.远程桌面连接时,同一个用户不能同时远程2个桌面连接. ----------- ...

  8. 使用mybatis报错【Result Maps collection already contains value for ...BaseResultMap】的解决方法

    Result Maps collection already contains value for ...BaseResultMap ...... 这个问题,相信大家在使用mybatis的重新生成 d ...

  9. spark-2.4.0-hadoop2.7-简单操作

    1. 说明 本文基于:spark-2.4.0-hadoop2.7-高可用(HA)安装部署 2. 启动Spark Shell 在任意一台有spark的机器上执行 # --master spark://m ...

  10. idea软件破解汉化

    →http://idea.lanyus.com/上可以找到最新的破解补丁,下载并放到软件的bin目录下  →更改bin目录下的两个文件:Idea.exe.vmoptions和Idea64.exe.vm ...