bzoj3467

来源:互联网 发布:约瑟夫环java环形链表 编辑:程序博客网 时间:2024/06/06 10:55

题意:
这里写图片描述
n<=100000

#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<iostream>#include<algorithm>#define N 110000#define maxd 16#define base 233#define lowbit(x) (x&(-x))#define LL long longusing namespace std;struct node{int o,x;}q[N];int sa[N][26],sb[N][26],al,bl,na,nb,wa[N],wb[N],n,par[N][18],h[N][18],cf[18],p[N],dep[N];int L[N],R[N],lt1[N],lt2[N],rk[N],mx;LL ans;inline int read(){    char c=getchar();int t=0;    while(c<'0' || c>'9') c=getchar();    while(c>='0' && c<='9') {t=t*10+c-'0';c=getchar();}    return t;}void dfs(int x,int fa,int c){    par[x][0]=fa;h[x][0]=c+1;    for(int i=1;i<=maxd;i++)         par[x][i]=par[par[x][i-1]][i-1],h[x][i]=h[x][i-1]+h[par[x][i-1]][i-1]*cf[i-1];    for(int i=0;i<26;i++) if(sb[x][i]) dfs(sb[x][i],x,i);}bool cmpb(int x,int y){    for(int i=maxd;i>=0;i--) if(h[x][i]==h[y][i]) x=par[x][i],y=par[y][i];    if(h[x][0]<h[y][0]) return 1;    return 0;}int kth(int x,int k){    k--;    for(int i=maxd;i>=0;i--) if(k&(1<<i)) x=par[x][i];    return h[x][0];}int tdl(int l,int r,int k,int c){    int res=0;c++;    while(l<=r)    {        int mid=(l+r)/2,t=kth(p[mid],k);        if(t>=c) {r=mid-1;if(t==c) res=mid;}        else l=mid+1;    }    return res;}int tdr(int l,int r,int k,int c){    int res=0;c++;    while(l<=r)    {        int mid=(l+r)/2,t=kth(p[mid],k);        if(t<=c) {l=mid+1;if(t==c) res=mid;}        else r=mid-1;    }    return res;}void dp(int x){    if(R[x]==0) return;    for(int i=0;i<26;i++)    {        int y=sa[x][i];        if(y)        {            dep[y]=dep[x]+1;            L[y]=tdl(L[x],R[x],dep[y],i);            R[y]=tdr(L[x],R[x],dep[y],i);            dp(y);        }    }}void change(int *lt,int x,int d){    for(int i=x;i<=mx;i+=lowbit(i)) lt[i]+=d;}int find(int *lt,int x){    int sum=0;    for(int i=x;i;i-=lowbit(i)) sum+=lt[i];    return sum;}int main(){    cf[0]=base;    for(int i=1;i<=maxd;i++) cf[i]=cf[i-1]*cf[i-1];    scanf("%d",&n);    na=nb=al=bl=1;wa[1]=wb[1]=1;    for(int i=1;i<=n;i++)    {        int o=read(),x=read();char c=getchar();        while(c<'a' || c>'z') c=getchar();        q[i].o=o;        if(o==1)        {            x=wa[x];na++;            if(sa[x][c-'a']==0) sa[x][c-'a']=++al;            wa[na]=sa[x][c-'a'];            q[i].x=wa[na];        }        else        {            x=wb[x];nb++;            if(sb[x][c-'a']==0) sb[x][c-'a']=++bl;            wb[nb]=sb[x][c-'a'];            q[i].x=wb[nb];        }    }    mx=max(al,bl)+1;    dfs(1,0,-1);    for(int i=1;i<=bl;i++) p[i]=i;    sort(p+1,p+bl+1,cmpb);    for(int i=1;i<=bl;i++) rk[p[i]]=i;    L[1]=1;R[1]=bl;    dp(1);    ans=1;    for(int i=1;i<=n;i++)    {        int o=q[i].o,x=q[i].x;        if(o==1)        {            if(R[x])            {                ans+=find(lt2,R[x])-find(lt2,L[x]-1);                change(lt1,L[x],1);change(lt1,R[x]+1,-1);            }        }        else        {            ans++;            ans+=find(lt1,rk[x]);            change(lt2,rk[x],1);        }        printf("%lld\n",ans);    }    return 0;}

题解:
膜了claris的题解。。
这题有个比较厉害的地方就是字典树预处理向上2k的哈希值,就可以O(nlog2n)字典序排序每个点到根的字符串了。。
先离线建出两棵字典树
将B树的所有点到根的串排序,A树中一个点能匹配的是连续的一段,可以二分处理出每个点匹配的区间。然后用两个树状数组模拟就好。。

0 0
原创粉丝点击