# 【洛谷6292】区间本质不同子串个数（后缀自动机+LCT）

### 代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define M 200000
#define LL long long
using namespace std;
int n,p[N+5];char s[N+5];LL ans[M+5];typedef pair<int,int> Pr;vector<Pr> q[N+5];
class SuffixAutomation//后缀自动机
{
private:
int lst;struct node {int L,F,S[30];}O[2*N+5];
public:
int Nt;I SuffixAutomation() {Nt=lst=1;}
I int operator [] (CI x) {return O[x].F;}I int operator () (CI x) {return O[x].L;}
I int Ins(CI x)//返回节点对应编号
{
RI p=lst,o=lst=++Nt;O[o].L=O[p].L+1;
W(p&&!O[p].S[x]) O[p].S[x]=o,p=O[p].F;if(!p) return O[o].F=1,o;
RI q=O[p].S[x];if(O[p].L+1==O[q].L) return O[o].F=q,o;
RI k=++Nt;(O[k]=O[q]).L=O[p].L+1,O[q].F=O[o].F=k;
W(p&&O[p].S[x]==q) O[p].S[x]=k,p=O[p].F;return o;
}
}SAM;
class TreeArray//区间修改+区间查询 树状数组
{
private:
LL a[N+5],b[N+5];I void U(RI x,CI v) {LL t=1LL*v*(x-1);W(x<=n) a[x]+=v,b[x]+=t,x+=x&-x;}
I LL Q(CI x) {RI i=x;LL t1=0,t2=0;W(i) t1+=a[i],t2+=b[i],i^=i&-i;return t1*x-t2;}
public:
I void U(CI l,CI r,CI v) {U(l,v),U(r+1,-v);}I LL Q(CI l,CI r) {return Q(r)-Q(l-1);}
}T;
{
private:
#define PD(x) O[x].G&&(Upt(O[x].S[0],O[x].G),Upt(O[x].S[1],O[x].G),O[x].G=0)
#define Upt(x,v) (O[x].V=O[x].G=v)
#define IR(x) (O[O[x].F].S[0]^x&&O[O[x].F].S[1]^x)
#define Wh(x) (O[O[x].F].S[1]==x)
#define Co(x,y,d) (O[O[x].F=y].S[d]=x)
int St[2*N+5];struct node {int V,G,F,S[2];}O[2*N+5];
I void Ro(CI x)
{
RI f=O[x].F,p=O[f].F,d=Wh(x);!IR(f)&&(O[p].S[Wh(f)]=x),O[x].F=p,
Co(O[x].S[d^1],f,d),Co(f,x,d^1);
}
I void S(CI x)
{
RI f=x,T=0;W(St[++T]=f,!IR(f)) f=O[f].F;W(T) PD(St[T]),--T;
W(!IR(x)) f=O[x].F,!IR(f)&&(Ro(Wh(x)^Wh(f)?x:f),0),Ro(x);
}
public:
I void Init() {for(RI i=1;i<=SAM.Nt;++i) O[i].F=SAM[i];}//建树
I void Ac(RI x,CI id)//Access染色
{
RI y=0;for(RI l,r;x;x=O[y=x].F) S(x),l=SAM(O[x].F)+1,r=SAM(x),//对应的子串长度
O[x].V&&(T.U(O[x].V-r+1,O[x].V-l+1,-1),0),O[x].S[1]=y;T.U(1,id,1),Upt(y,id);//清空原贡献，最后加上新贡献
}
}LCT;
int main()
{
RI Qt,i,x,y;for(scanf("%s",s+1),n=strlen(s+1),i=1;i<=n;++i) p[i]=SAM.Ins(s[i]&31);//初始化建后缀自动机
for(scanf("%d",&Qt),i=1;i<=Qt;++i) scanf("%d%d",&x,&y),q[y].push_back(make_pair(i,x));//离线
RI j,s;for(LCT.Init(),i=1;i<=n;++i) for(LCT.Ac(p[i],i),//枚举右端点，每次更新LCT
j=0,s=q[i].size();j^s;++j) ans[q[i][j].first]=T.Q(q[i][j].second,i);//直接树状数组上询问左端点答案
for(i=1;i<=Qt;++i) printf("%lld\n",ans[i]);return 0;
}

posted @ 2020-07-21 12:10  TheLostWeak  阅读(157)  评论(0编辑  收藏