bzoj3467: Crash和陶陶的游戏

就一篇题解:

BZOJ3467 : Crash和陶陶的游戏 - weixin_34248487的博客 - CSDN博客

1.离线,建出Atrie树;B树的倍增哈希数组,节点按照到根路径字典序排序

2.处理A节点对应前缀对应B中的极长可以匹配的区间。在父亲节点区间内二分即可

3.更新答案:

①加入A点,找区间中B中已经出现点个数。树状数组

②加入B点,本质是B到根的字符串放在trie最大匹配长度,二分,哈希表存A树是否有这个前缀,得到的长度就是当前匹配长度。

 

直上直下的链本质是字符串的前缀后缀。

动态更新hash很难,就离线,在可能贡献的集合内找到当前出现的。

 

假装有代码.jpg

 

这个是两个logn的

 

可以变成一个logn!

sort是不必要的,

对于②B树点对trie的影响,不妨直接倍增+hash找到最长的匹配位置y,在y的位置++,然后①时候子树查询即可!

通过提前打好标记使得不用同时考虑很多!

(类似预处理)

还有可能一个点有多个c儿子,要合并成一个。①的时候整个子树++,表示到根的路径上多了一个点,②的时候,匹配最长位置单点查询这个值

两个树状数组

 

注意,unsigned long long哈希

单模数随便rand就卡掉了

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define ul unsigned long long
#define ll unsigned long long
using namespace std;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}

namespace Miracle{
const int N=2e5+5;
const ul base=233;
const int orz=100000;

struct HA{
    int nxt[N],hd[N],cnt;
    ul val[N];
    int id[N];
    void ins(int x,ll h){
        int pos=h%orz;
        nxt[++cnt]=hd[pos];hd[pos]=cnt;val[cnt]=h;
        id[cnt]=x;
    }
    int query(ll h){
        int pos=h%orz;
        for(reg i=hd[pos];i;i=nxt[i]){
            if(val[i]==h) return id[i];
        }
        return -1;
    }
}ha;
//trie
int ch[N][26];
int id[N];//is
int n;
int tot;
int lp;
ul pw[(1<<17)+233];
void ins(int x,int c){
    ++lp;
    x=id[x];
//    cout<<" true fa "<<x<<" ch "<<ch[x][c]<<endl;
    if(ch[x][c]){
        id[lp]=ch[x][c];return;
    }
    id[lp]=++tot;
    ch[x][c]=tot;
}
int dfn[N],df,dfn2[N];
void fin(int x,ul haxi,int d){
    dfn[x]=++df;
    if(x!=1){
        ha.ins(x,haxi);
    }
    for(reg i=0;i<26;++i){
        if(ch[x][i]){
            fin(ch[x][i],haxi+(ll)pw[d]*(i+1),d+1);
        }
    }
    dfn2[x]=df;
}
//B tree
int cur;
struct node{
    int nxt,to;
    int val;
}e[2*N];
int hd[N],cnt;
void add(int x,int y,int z){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    e[cnt].val=z;
    hd[x]=cnt;
}
int fa[N][18];
ul hsh[N][18];
void dfs(int x){
    for(reg i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        fa[y][0]=x;
        hsh[y][0]=e[i].val+1;
        dfs(y);
    }
}
//question
struct que{
    int typ,fa,c;
    int x;
}q[N];

int get(int x){
    ll now=0;
    int has=0;
    int ret=0;
    for(reg j=17;j>=0;--j){
        if(!fa[x][j]) continue;
        ll tmp=((ll)now+pw[has]*hsh[x][j]);
        int nc=ha.query(tmp);
        if(nc!=-1){
            ret=nc;
            now=tmp;
            has+=(1<<j);
            x=fa[x][j];//shit
        }
    }
    return ret;
}

struct treearray{
    int f[N];
    int n;
    void upda(int x,int c){
        for(;x<=n;x+=x&(-x)) f[x]+=c;
    }
    int query(int x){
        int ret=0;
        for(;x;x-=x&(-x)) ret+=f[x];return ret;
    }
}t1,t2;
int main(){
    rd(n);
    char s[233];
    ++tot;++cur;//start
    lp=1;
    id[1]=1;
    
    ll ans=0;
    ans=1;//1 1
    for(reg i=1;i<=n;++i){
        rd(q[i].typ);rd(q[i].fa);//rd(q[i].c);
        scanf("%s",s+1);q[i].c=s[1]-'a';
        if(q[i].typ==1){
            ins(q[i].fa,q[i].c);
            q[i].x=id[lp];
//            prt(id,1,lp);
        }else{
            ++cur;
            q[i].x=cur;
            add(q[i].fa,cur,q[i].c);
        }
//        cout<<tot<<" ";
    }
//    cout<<endl<<endl;
    dfs(1);
//    cout<<"after dfs "<<tot<<endl;
//    prt(id,1,lp);
    
    pw[0]=1;
    for(reg i=1;i<=(1<<17);++i){
        pw[i]=(ll)pw[i-1]*base;//%mod;
    }
    for(reg j=1;j<=17;++j){
        for(reg i=1;i<=cur;++i){
            fa[i][j]=fa[fa[i][j-1]][j-1];
            hsh[i][j]=((ll)hsh[i][j-1]+(ll)hsh[fa[i][j-1]][j-1]*pw[1<<(j-1)]);//%mod)%mod;
        }
    }
//    cout<<"after bezeng "<<endl;
    fin(1,0,0);
//    cout<<" after fin "<<endl;
    t1.n=t2.n=tot;
//    cout<<" tot "<<tot<<endl;
//    prt(dfn,1,tot);
//    cout<<" dfn2-------------------------- "<<endl;
//    prt(dfn2,1,tot);
    int tc=0,tb=0;
    for(reg i=1;i<=n;++i){
        if(q[i].typ==1){//add trie
            ++tc;
//            cout<<"trie "<<endl;
            int x=q[i].x;//ch[id[q[i].fa]][q[i].c];
//            cout<<"x "<<x<<" tc "<<tc<<endl;
            ans+=t1.query(dfn2[x])-t1.query(dfn[x]-1);
            t2.upda(dfn[x],1);t2.upda(dfn2[x]+1,-1);
        }else{//add B tree
            ++tb;
//            cout<<" Btree "<<endl;
//            cout<<" x "<<q[i].x<<endl;
            int y=get(q[i].x);
//            cout<<" y "<<y<<" tb "<<tb<<" dfn "<<dfn[y]<<endl;
            if(y){
                ans+=t2.query(dfn[y]);
                t1.upda(dfn[y],1);
            }
            ++ans;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

}
signed main(){
//    freopen("5.in","r",stdin);
//    freopen("my.out","w",stdout);
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/3/26 18:56:24
*/
View Code

 

posted @ 2019-03-21 19:41  *Miracle*  阅读(296)  评论(0编辑  收藏  举报