一、P6164 【模板】后缀平衡树
题解:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#define ll long long
#define llu unsigned ll
#define pr make_pair
#define pb push_back
//#define lc (cnt<<1)
//#define rc (cnt<<1|1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e15;
const int mod=998244353;
const double eps=1e-8;
const double alpha=0.75;
const int maxn=3000100;
struct node
{
int lc,rc;
int si;
double key;
}t[maxn];
int res[maxn],rcnt,rt;
char s[maxn],str[maxn];
int *bad=NULL;
pair<double,double>par;
void decodeWithMask(char *s,int mask)
{
int len=strlen(s);
for(int i=0;i<len;i++)
{
mask=(mask*131+i)%len;
swap(s[i],s[mask]);
}
}
bool balance(int p)
{
return (double)t[t[p].lc].si<=t[p].si*alpha&&(double)t[t[p].rc].si<=t[p].si*alpha;
}
void pushup(int p)
{
t[p].si=t[t[p].lc].si+t[t[p].rc].si+1;
}
void dfs(int p)
{
if(!p) return ;
dfs(t[p].lc);
res[++rcnt]=p;
dfs(t[p].rc);
}
int build(int l,int r,double lkey,double rkey)
{
if(l>r) return 0;
int mid=(l+r)>>1;
int p=res[mid];
t[p].key=(lkey+rkey)/2;
t[p].lc=build(l,mid-1,lkey,t[p].key);
t[p].rc=build(mid+1,r,t[p].key,rkey);
pushup(p);
return p;
}
void re_build(int *p)
{
rcnt=0;
dfs(*p);
(*p)=build(1,rcnt,par.first,par.second);
}
bool cmp(int x,int y)
{
return s[x]<s[y]||(s[x]==s[y]&&t[x-1].key<t[y-1].key);
}
void _insert(int &p,int xid,double lkey,double rkey)
{
if(!p)
{
p=xid;
t[p].si=1;
t[p].key=(lkey+rkey)/2;
t[p].lc=t[p].rc=0;
bad=NULL;
return ;
}
if(cmp(xid,p)) _insert(t[p].lc,xid,lkey,t[p].key);
else _insert(t[p].rc,xid,t[p].key,rkey);
pushup(p);
if(!balance(p)) bad=&p,par=pr(lkey,rkey);
}
void __insert(int &rt,int xid)
{
_insert(rt,xid,0,dnf);
if(bad!=NULL)
re_build(bad);
}
void _delete(int &p,int xid)
{
if(p==xid)
{
if(!t[p].lc||!t[p].rc)
{
p=t[p].lc|t[p].rc;
}
else
{
int rmax=t[p].lc,last=p;
while(t[rmax].rc)
{
last=rmax;
t[last].si--;
rmax=t[rmax].rc;
}
if(last==p)
{
t[rmax].rc=t[p].rc;
p=rmax;
pushup(p);
}
else
{
t[rmax].lc=t[p].lc;
t[rmax].rc=t[p].rc;
t[last].rc=0;
p=rmax;
pushup(p);
}
}
return ;
}
if(cmp(xid,p)) _delete(t[p].lc,xid);
else _delete(t[p].rc,xid);
pushup(p);
}
bool cmp(int now)
{
for(int p=1;str[p];p++,now=(now?now-1:0))
{
if(str[p]<s[now]) return true;
else if(str[p]>s[now]) return false;
}
}
int ask(int p)
{
if(!p) return 0;
if(cmp(p)) return ask(t[p].lc);
else return t[t[p].lc].si+1+ask(t[p].rc);
}
int main(void)
{
int n;
scanf("%d",&n);
scanf("%s",s+1);
int mask=0;
int nlen=strlen(s+1);
for(int i=1;i<=nlen;i++) __insert(rt,i);
char op[10];
for(int i=1;i<=n;i++)
{
scanf("%s",op);
if(op[0]=='A')
{
scanf("%s",str+1);
decodeWithMask(str+1,mask);
int len=strlen(str+1);
for(int j=1;j<=len;j++)
{
s[nlen+j]=str[j];
__insert(rt,nlen+j);
}
nlen+=len;
}
else if(op[0]=='D')
{
int k;
scanf("%d",&k);
for(int j=nlen;j>nlen-k;j--)
_delete(rt,j);
nlen-=k;
}
else
{
scanf("%s",str+1);
decodeWithMask(str+1,mask);
int len=strlen(str+1);
reverse(str+1,str+len+1);
str[len+1]='Z'+1;
str[len+2]=0;
int ans=ask(rt);
str[len]--;
ans-=ask(rt);
printf("%d\n",ans);
mask^=ans;
}
}
return 0;
}
二、P5353 树上后缀排序
注意:这题 x 所代表的字符串应该是由 fa [ x ] 转移而来。
若x,y的 fa 不同,那么他们的 fa 所代表的字符串一定已经分出大小。
题解:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#define ll long long
#define llu unsigned ll
#define pr make_pair
#define pb push_back
//#define lc (cnt<<1)
//#define rc (cnt<<1|1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e15;
const int mod=998244353;
const double eps=1e-8;
const double alpha=0.75;
const int maxn=500100;
struct node
{
int lc,rc;
int si;
double key;
}t[maxn];
int fa[maxn];
int res[maxn],rcnt,rt;
int sa[maxn],sacnt,rk[maxn];
char s[maxn],str[maxn];
int *bad=NULL;
pair<double,double>par;
bool balance(int p)
{
return (double)t[t[p].lc].si<=t[p].si*alpha&&(double)t[t[p].rc].si<=t[p].si*alpha;
}
void pushup(int p)
{
t[p].si=t[t[p].lc].si+t[t[p].rc].si+1;
}
void dfs(int p)
{
if(!p) return ;
dfs(t[p].lc);
res[++rcnt]=p;
dfs(t[p].rc);
}
int build(int l,int r,double lkey,double rkey)
{
if(l>r) return 0;
int mid=(l+r)>>1;
int p=res[mid];
t[p].key=(lkey+rkey)/2;
t[p].lc=build(l,mid-1,lkey,t[p].key);
t[p].rc=build(mid+1,r,t[p].key,rkey);
pushup(p);
return p;
}
void re_build(int *p)
{
rcnt=0;
dfs(*p);
(*p)=build(1,rcnt,par.first,par.second);
}
bool cmp(int x,int y)
{
return s[x]<s[y]||(s[x]==s[y]&&t[fa[x]].key<t[fa[y]].key);
}
void _insert(int &p,int xid,double lkey,double rkey)
{
if(!p)
{
p=xid;
t[p].si=1;
t[p].key=(lkey+rkey)/2;
t[p].lc=t[p].rc=0;
bad=NULL;
return ;
}
if(cmp(xid,p)) _insert(t[p].lc,xid,lkey,t[p].key);
else _insert(t[p].rc,xid,t[p].key,rkey);
pushup(p);
if(!balance(p)) bad=&p,par=pr(lkey,rkey);
}
void __insert(int &rt,int xid)
{
_insert(rt,xid,0,dnf);
if(bad!=NULL)
re_build(bad);
}
void dfsForSa(int p)
{
if(!p) return ;
dfsForSa(t[p].lc);
sa[++sacnt]=p;
dfsForSa(t[p].rc);
}
void buildTree(int n)
{
for(int i=1;i<=n;i++)
__insert(rt,i);
dfsForSa(rt);
for(int i=1;i<=n;i++) rk[sa[i]]=i;
}
int main(void)
{
int n;
scanf("%d",&n);
for(int i=2;i<=n;i++)
scanf("%d",&fa[i]);
scanf("%s",s+1);
buildTree(n);
for(int i=1;i<=n;i++)
printf("%d ",sa[i]);
return 0;
}
三、P2408 不同子串个数
(一)每次插入后通过查询维护height:这样就实现了动态维护height,注意这个height的含义是 位置为i的后缀(其排名为rank[i])与排名为rank[i]-1的后缀的lcp
也可以链表维护前后排名所指向的节点,插入完成时维护 height(需要讨论当前节点是父亲节点的哪个儿子)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#define ll long long
#define llu unsigned ll
#define pr make_pair
#define pb push_back
//#define lc (cnt<<1)
//#define rc (cnt<<1|1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e15;
const int mod=998244353;
const double eps=1e-8;
const double alpha=0.75;
const int maxn=100100;
const int p=131;
struct node
{
int lc,rc;
int si;
double key;
}t[maxn];
int res[maxn],rcnt,rt;
int height[maxn];
llu pw[maxn],has[maxn];
char s[maxn];
int *bad=NULL;
pair<double,double>par;
bool balance(int p)
{
return (double)t[t[p].lc].si<=t[p].si*alpha&&(double)t[t[p].rc].si<=t[p].si*alpha;
}
void pushup(int p)
{
t[p].si=t[t[p].lc].si+t[t[p].rc].si+1;
}
void dfs(int p)
{
if(!p) return ;
dfs(t[p].lc);
res[++rcnt]=p;
dfs(t[p].rc);
}
int build(int l,int r,double lkey,double rkey)
{
if(l>r) return 0;
int mid=(l+r)>>1;
int p=res[mid];
t[p].key=(lkey+rkey)/2;
t[p].lc=build(l,mid-1,lkey,t[p].key);
t[p].rc=build(mid+1,r,t[p].key,rkey);
pushup(p);
return p;
}
void re_build(int *p)
{
rcnt=0;
dfs(*p);
(*p)=build(1,rcnt,par.first,par.second);
}
bool cmp(int x,int y)
{
return s[x]<s[y]||(s[x]==s[y]&&t[x-1].key<t[y-1].key);
}
bool eq(int l1,int l2,int len)
{
int r1=l1+len-1,r2=l2+len-1;
return has[r1]-has[l1-1]*pw[len]==has[r2]-has[l2-1]*pw[len];
}
int getlcp(int x,int y)
{
int l=1,r=min(x,y),ans=0;//二分长度
while(l<=r)
{
int mid=(l+r)>>1;
if(eq(x-mid+1,y-mid+1,mid)) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
void _insert(int &p,int xid,double lkey,double rkey)
{
if(!p)
{
p=xid;
t[p].si=1;
t[p].key=(lkey+rkey)/2;
t[p].lc=t[p].rc=0;
bad=NULL;
return ;
}
if(cmp(xid,p)) _insert(t[p].lc,xid,lkey,t[p].key);
else _insert(t[p].rc,xid,t[p].key,rkey);
pushup(p);
if(!balance(p)) bad=&p,par=pr(lkey,rkey);
}
int findRank(int p,int xid)
{
if(p==xid) return t[t[p].lc].si+1;
if(cmp(xid,p)) return findRank(t[p].lc,xid);
else return t[t[p].lc].si+1+findRank(t[p].rc,xid);
}
int findId(int p,int k)
{
if(!p) return 0;
if(t[t[p].lc].si==k-1) return p;
if(t[t[p].lc].si>=k) return findId(t[p].lc,k);
else return findId(t[p].rc,k-t[t[p].lc].si-1);
}
void __insert(int &rt,int xid)
{
has[xid]=has[xid-1]*p+s[xid];
_insert(rt,xid,0,dnf);
if(bad!=NULL)
re_build(bad);
int k=findRank(rt,xid);
int pre=findId(rt,k-1);
int nt=findId(rt,k+1);
height[xid]=getlcp(pre,xid);
height[nt]=getlcp(xid,nt);
}
void buildTree(int n)
{
for(int i=1;i<=n;i++)
__insert(rt,i);
}
int main(void)
{
int n;
scanf("%d",&n);
scanf("%s",s+1);
reverse(s+1,s+n+1);
pw[0]=1;
for(int i=1;i<=n;i++)
pw[i]=pw[i-1]*p;
buildTree(n);
ll ans1=1ll*n*(n+1)/2;
ll ans2=0;
for(int i=1;i<=n;i++)
ans2+=height[i];
printf("%lld\n",ans1-ans2);
return 0;
}
(二)处理结束时,维护sa,rank,然后维护height
不知道是我姿势的问题,还是这玩意就是常数有点大。。。
后缀数组88ms,这个东西408ms。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#define ll long long
#define llu unsigned ll
#define pr make_pair
#define pb push_back
//#define lc (cnt<<1)
//#define rc (cnt<<1|1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e15;
const int mod=998244353;
const double eps=1e-8;
const double alpha=0.75;
const int maxn=500100;
struct node
{
int lc,rc;
int si;
double key;
}t[maxn];
int res[maxn],rcnt,rt;
int sa[maxn],sacnt,rk[maxn],height[maxn];
char s[maxn];
int *bad=NULL;
pair<double,double>par;
bool balance(int p)
{
return (double)t[t[p].lc].si<=t[p].si*alpha&&(double)t[t[p].rc].si<=t[p].si*alpha;
}
void pushup(int p)
{
t[p].si=t[t[p].lc].si+t[t[p].rc].si+1;
}
void dfs(int p)
{
if(!p) return ;
dfs(t[p].lc);
res[++rcnt]=p;
dfs(t[p].rc);
}
int build(int l,int r,double lkey,double rkey)
{
if(l>r) return 0;
int mid=(l+r)>>1;
int p=res[mid];
t[p].key=(lkey+rkey)/2;
t[p].lc=build(l,mid-1,lkey,t[p].key);
t[p].rc=build(mid+1,r,t[p].key,rkey);
pushup(p);
return p;
}
void re_build(int *p)
{
rcnt=0;
dfs(*p);
(*p)=build(1,rcnt,par.first,par.second);
}
bool cmp(int x,int y)
{
return s[x]<s[y]||(s[x]==s[y]&&t[x+1].key<t[y+1].key);
}
void _insert(int &p,int xid,double lkey,double rkey)
{
if(!p)
{
p=xid;
t[p].si=1;
t[p].key=(lkey+rkey)/2;
t[p].lc=t[p].rc=0;
bad=NULL;
return ;
}
if(cmp(xid,p)) _insert(t[p].lc,xid,lkey,t[p].key);
else _insert(t[p].rc,xid,t[p].key,rkey);
pushup(p);
if(!balance(p)) bad=&p,par=pr(lkey,rkey);
}
void __insert(int &rt,int xid)
{
_insert(rt,xid,0,dnf);
if(bad!=NULL)
re_build(bad);
}
void dfsForSa(int p)
{
if(!p) return ;
dfsForSa(t[p].lc);
sa[++sacnt]=p;
dfsForSa(t[p].rc);
}
void buildTree(int n)
{
for(int i=n;i>=1;i--)
__insert(rt,i);
dfsForSa(rt);
for(int i=1;i<=n;i++) rk[sa[i]]=i;
}
void getheight(int n)
{
int k=0;
for(int i=1;i<=n;i++)
{
if(k) k--;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k]) k++;
height[i]=k;
}
}
int main(void)
{
int n;
scanf("%d",&n);
scanf("%s",s+1);
buildTree(n);
getheight(n);
ll ans1=1ll*n*(n+1)/2;
ll ans2=0;
for(int i=1;i<=n;i++)
ans2+=height[i];
printf("%lld\n",ans1-ans2);
return 0;
}