做了三天,实在太坑了
终于100文章了
这个题要求每次在单词的末尾加一个字母,再查询本质不同的串的个数、、
既然是子串满足连续性,那就可以后缀数组+lcp搞了;
具体计算方式:
由于后缀数组的开头是包括所有子串开头的,所以便利sa即可出解。
具体要怎么做?
先放宽条件:如果只有一次查询,对字符串建好后缀数组后,由于sa相临的后缀的前缀一定是最相似的,所以重复的情况一定出现在这两个串中,对于这两个串的lcp,一定是会被算两次的 : 如12 2121 和12 1 第一个可拆成1、 12、 122、 1221、 12212、 122121 ;;第二个串可拆成1、 12、 121 可以发现lcp”1、 12“被算了两次,所以在计算第二个串时要减去和第一个串的lcp;;
看直观的表 :
但是它是每一次加就有一次询问,而且加的时候对每个后缀都有影响,可能会导致lcp的改变,,那么怎么办呢?
其实可以把串反转,,因为根据每个串的末端也可以找出所有的子串;;
这样一次就只用加一个字符串了;
但是,这似乎就需要动态维护sa了、、、、、
询问xyx: 这不是可以log n 找位置吗;;
询问shallwe: 我没空啊,你去问cjc、
询问cjc: xym研究过后缀数组动态加后缀,你可以去问他;
询问xym: 用splay离线操作加点啊,shallwe 跑的比我的快,你可以问他、、
、、、、、、、、、、、、、、、、、、、、、、、
然后就只能自己看题解了,因为splay维护sa太玄学
然而题解更玄学、
所以打了个splay
千万不要用 log 函数!!!!!
!!
!
!
!
!!!
!
!
!
!!!!!
而且lcp时要想清楚
码
#include<iostream>
#include<cstdio>
using namespace std;
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#define N 300009
#define inf 1e9+10
#define ll long long
map<ll,ll>ma;
ll max1,min1;
struct tree
{
ll zhi;
tree *ch[2],*fu;
ll getwh()
{
return fu->ch[0]==this?0:1;
}
void lian(ll wh,tree *child);
}p[200001],*null,*root;
ll tot;
void tree::lian(ll wh,tree *child){
ch[wh]=child;
if(child!=null)
child->fu=this;
}
tree *jian(ll k)
{
tree *now=p+ ++tot;
now->zhi=k;
now->ch[1]=now->ch[0]=now->fu=null;
return now;
}
void rotate(tree *&k)
{
tree *fu=k->fu;
tree *ye=k->fu->fu;
ll wh=k->getwh();
fu->lian(wh,k->ch[wh^1]);
k->lian(wh^1,fu);
k->fu=ye;
if(ye!=null)
ye->ch[ye->ch[0]==fu?0:1]=k;
}
void splay(tree *now,tree *tar)
{
for(;now->fu!=tar;rotate(now))
if(now->fu->fu!=tar)now->fu->getwh()==now->getwh()?rotate(now->fu):rotate(now);
if(tar==null)
root=now;
}
void ins(ll k)
{
tree *now=root,*last=null,*newone=jian(k);
while(now!=null)
{last=now;
if(k>now->zhi)
min1=max(min1,now->zhi),now=now->ch[1];
else if(k<now->zhi)max1=min(max1,now->zhi),now=now->ch[0];
}
if(last==null)
{
root=newone;
return;
}
if(last->zhi>k)
{
last->lian(0,newone);
}else
{
last->lian(1,newone);
}
}
ll n,s1[N],s2[N],cc[N],sa[N],height[N],rank[N],i,j,k,s[N],f[N][21];
ll ans;
inline bool cmp(ll *y, ll a, ll b, ll k) {
ll arank1 = y[a];
ll brank1 = y[b];
ll arank2 = a + k >= n ? -1 : y[a + k];
ll brank2 = b + k >= n ? -1 : y[b + k];
return arank1 == brank1 && arank2 == brank2;
}
inline void da() {
ll *x = s1, *y = s2;
ll m = 100005;
for (ll i = 0; i < m; i++) cc[i] = 0;
for (ll i = 0; i < n; i++) ++cc[x[i] = s[i]];
for (ll i = 1; i < m; i++) cc[i] += cc[i - 1];
for (ll i = n - 1; i >= 0; i--) sa[--cc[x[i]]] = i;
for (ll k = 1; k <= n; k <<= 1) {
ll p = 0;
for (ll i = n - k; i < n; i++) y[p++] = i;
for (ll i = 0; i < n; i++)
if (sa[i] >= k) y[p++] = sa[i] - k;
for (ll i = 0; i < m; i++) cc[i] = 0;
for (ll i = 0; i < n; i++) ++cc[x[y[i]]];
for (ll i = 1; i < m; i++) cc[i] += cc[i - 1];
for (ll i = n - 1; i >= 0; i--) sa[--cc[x[y[i]]]] = y[i];
swap(x, y);
m = 1; x[sa[0]] = 0;
for (ll i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i], sa[i - 1], k) ? m - 1 : m++;
if (m >= n) break;
}
}
inline void calcheight() {
for (ll i = 0; i < n; i++) rank[sa[i]] = i;
height[0] = 0;
ll k = 0;
for (ll i = 0; i < n; i++) {
if (!rank[i]) continue;
ll j = sa[rank[i] - 1];
if (k) k--;
while (s[i + k] == s[j + k]) k++;
height[rank[i]] =f[rank[i]][0]=k;
}
}
void rmq()
{
for(i=1;i<=20;i++)
{
for(j=0;j+(1<<i)-1<=n;j++)
{
f[j][i]=min(f[j][i-1],f[j+(1<<(i-1))][i-1]);
}
}
}
ll woc[100001],lg2[200001];
int main()
{
null=p;
null->zhi=0;
null->fu=null->ch[0]=null->ch[1]=null;
root=null;
lg2[1]=0;lg2[2]=1;lg2[3]=1;
for(i=2;i<=16;i++)
{
int beg=1<<i;
int end=1<<(i+1);
for(j=beg;j<end;j++)lg2[j]=i;
}
scanf("%lld",&n);
for(i=n-1;i>=0;i--) scanf("%lld",&s[i]),woc[i]=s[i];
sort(woc,woc+n);
ll cnt=-1;
for(i=0;i<n;i++)
{
if(!ma[woc[i]])ma[woc[i]]=++cnt;
}
for(i=0;i<n;i++)s[i]=ma[s[i]];
da();calcheight();
rmq();
for(i=n-1;i>=0;i--)
{
max1=inf;
min1=-1;
ll k=rank[i],biao,lin1;
ins(k);
if(max1==inf&&min1==-1)
{
ans+=n-i;
printf("%lld\n",ans);
}
else
if(max1==inf&&min1!=-1)
{
min1++;
biao=(lg2[k-min1+1]);
lin1=min(f[min1][biao],f[k-(1<<biao)+1][biao]);
ans+=n-i-lin1;
printf("%lld\n",ans);
}else
if(max1!=inf&&min1==-1)
{
k++;
biao=lg2[max1-k+1];
lin1=min(f[k][biao],f[max1-(1<<biao)+1][biao]);
ans+=n-i-lin1;
printf("%lld\n",ans);
}
else
{
min1++;
biao=lg2[max1-min1+1];
lin1=min(f[min1][biao],f[max1-(1<<biao)+1][biao]);
ans-= (n-sa[max1])-lin1;
biao=lg2[k-min1+1];
lin1=min(f[min1][biao],f[k-(1<<biao)+1][biao]);
ans+=(n-i)-lin1;
k++;
biao=lg2[max1-k+1];
lin1=min(f[k][biao],f[max1-(1<<biao)+1][biao]);
ans+=(n-sa[max1])-lin1;
printf("%lld\n",ans);
}
}
}