[spoj11482]Count on a trie 解题报告

15 篇文章 0 订阅
11 篇文章 0 订阅

一开始以为是AC自动机的题,发现一直不会求T的AC自动机。后来想到可以求S的sa,就发现简单多了!
我们可以dfs S,然后对于S中的一个节点处理它的询问。(二分+hash比较大小)
那么问题就在于怎么维护T的hash。本来想用可持久化块链,发现mle了。就只好学了下treap。
treap的话,如果把rank看成下标,把随机的值看成权值的话,其实就是一颗随机数列上的笛卡尔树。树高等于比前面的数都大的数的个数的期望数量,那么在位置i的数被选的概率是 1i ,所以树高就是调和级数,就是 O(lnn)
treap有一个非常好的性质就是树的形态是确定的。而且如果两棵treap满足一棵树完全小于另一棵树,那么它们就是可以merge的,merge起来就是跟左偏树一样就可以了。
然后发现这道题的操作就是完全的裸merge。。

本来写的普通的hash被成功卡常了。。改成自然溢出就跑得飞快。
代码:

#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cassert>
const int Q=3e5+5;
const int S=1e5+5,T=3e5+5;
const int Len=1e5+5;
const int Sigma=26;
const int inf=1e5+1;
int n=1;
int a[S];

int stack[S],top;

typedef long long LL;
const int base=317;
int power[Len];

int next[S],succ[S],ptr[S],etot=1;
void addedge(int from,int to){
    //printf("Addedge(%d)=(%d,%d)\n",etot,from,to);
    next[etot]=ptr[from],ptr[from]=etot,succ[etot++]=to;
}
const int Log=16;
int fa[S],depth[S];
int q[S];
int shash[S];
void bfs(){
    q[0]=1;
    for(int h=0,t=1;h!=t;++h){
        shash[q[h]]=shash[fa[q[h]]]*base+a[q[h]];
        depth[q[h]]=depth[fa[q[h]]]+1;
        for(int i=ptr[q[h]];i;i=next[i]){
            fa[succ[i]]=q[h];
            q[t++]=succ[i];
        }
    }
}
int cnts[S];
int sa[S],nextsa[S];
int rank[S],nextrank[S];
vector<int> son[S];
void build_sa(){
    for(int i=n;i;--i)++cnts[rank[i]=a[i]];
    for(int i=1;i<=n;++i)cnts[i]+=cnts[i-1];
    for(int i=n;i;--i)sa[cnts[rank[i]]--]=i;
    bool flag;
    for(;;){
        flag=1;
        for(int i=n;i;--i)
            if(fa[i]){
                flag=0;
                break;
            }
        if(flag)break;

        /*printf("sa=\n");
        for(int i=1;i<=n;++i)printf("%d:%d\n",i,sa[i]);
        printf("rank=\n");
        for(int i=1;i<=n;++i)printf("%d:%d\n",i,rank[i]);
        puts("");*/

        memset(cnts,0,sizeof(cnts));
        for(int i=n;i;--i)++cnts[rank[i]];
        for(int i=1;i<=n;++i)cnts[i]+=cnts[i-1];

        for(int i=n;i;--i)son[i].clear();
        for(int i=n;i;--i)
            if(fa[i])
                son[fa[i]].push_back(i);
        for(int i=n;i;--i)
            for(int j=son[sa[i]].size();j--;){
                //printf("Get %d at %d\n",j,sa[i]);
                nextsa[cnts[rank[son[sa[i]][j]]]--]=son[sa[i]][j];
            }
        for(int i=n;i;--i)
            if(!fa[i])
                nextsa[cnts[rank[i]]--]=i;
        memcpy(sa,nextsa,sizeof(sa));

        flag=1;
        for(int i=1;i<=n;++i)
            if(rank[sa[i]]==rank[sa[i-1]]&&rank[fa[sa[i]]]==rank[fa[sa[i-1]]]){
                nextrank[sa[i]]=nextrank[sa[i-1]];
                flag=0;
            }
            else nextrank[sa[i]]=i;
        memcpy(rank,nextrank,sizeof(rank));
        if(flag)break;

        for(int i=n;i--;)fa[q[i]]=fa[fa[q[i]]];
    }

    /*printf("sa=\n");
    for(int i=1;i<=n;++i)printf("%d:%d\n",i,sa[i]);
    printf("rank=\n");
    for(int i=1;i<=n;++i)printf("%d:%d\n",i,rank[i]);
    puts("");*/
}
int gethash(int spos,int l){
    return spos-l<0?-1:shash[stack[spos]]-shash[stack[spos-l]]*power[l];
}

int thash[T],size[T];
struct TS{
    int ch[2];
    int c;
    int key;
    int hash;
    int size;
}bst[10000000];
int root[T];
int btot=1;
int rand_32(){
    return rand()<<17^rand()<<10^rand();
}
void out(int node){
    printf("treap(%d)={ch[0]=%d,ch[1]=%d,c=%d,hash=%d,size=%d}\n",node,bst[node].ch[0],bst[node].ch[1],bst[node].c,bst[node].hash,bst[node].size);
}
int newnode(int hash){
    bst[btot]=(TS){0,0,rand_32(),hash,1};
    return btot++;
}
void pushup_treap(int node){
    bst[node].hash=bst[bst[node].ch[1]].hash+bst[node].c*power[bst[bst[node].ch[1]].size]+bst[bst[node].ch[0]].hash*power[bst[bst[node].ch[1]].size+1];
    bst[node].size=bst[bst[node].ch[0]].size+bst[bst[node].ch[1]].size+1;
    //printf("%d(%d)->%d\n",bst[bst[node].ch[1]].hash,bst[bst[node].ch[1]].size,bst[node].hash);
}
void merge(int &node,int u,int v){
    //cout<<"Merge("<<u<<','<<v<<")\n";
    if(!u&&!v){
        node=0;
        return;
    }
    node=btot++;
    if(!u){
        bst[node]=bst[v];

        //pushup_treap(node);
        //out(node);

        return;
    }
    if(!v){
        bst[node]=bst[u];

        //pushup_treap(node);
        //out(node);

        return;
    }
    if(bst[u].key>bst[v].key){
        bst[node]=bst[u];
        merge(bst[node].ch[1],bst[u].ch[1],v);
    }
    else{
        bst[node]=bst[v];
        merge(bst[node].ch[0],u,bst[v].ch[0]);
    }
    pushup_treap(node);

    //out(node);

}
int cmp(int spos,int node){
    //printf("---cmp(%d,%d)--\n",stack[spos],node);
    int ans;
    for(;node;){
        //cout<<"Gethash("<<stack[spos]<<","<<bst[bst[node].ch[1]].size+1<<")\n";
        //printf("hash(%d)=%d\n",node,(bst[node].c*power[bst[bst[node].ch[1]].size+1]+bst[bst[node].ch[1]].hash)%Mod);
        //out(node);
        if(gethash(spos,bst[bst[node].ch[1]].size+1)==bst[node].c*power[bst[bst[node].ch[1]].size]+bst[bst[node].ch[1]].hash){
            spos-=bst[bst[node].ch[1]].size+1;
            node=bst[node].ch[0];
            //cout<<"into left\n";
        }
        else{
            ans=node;
            node=bst[node].ch[1];
            //cout<<"into right\n";
        }
    }
    //printf("=%d\n",a[stack[spos]]<bst[ans].c?-1:1);
    return a[stack[spos]]<bst[ans].c?-1:1;
}
int compare(int qs,int qt){
    //printf("compare(%d,%d)\n",qs,qt);
    if(gethash(qs=depth[qs]-1,size[qt])==thash[qt])return 0;
    else return cmp(qs,root[qt]);
}

struct SS{
    int l,r;
    int size;
}segt[S<<2];
#define lson node<<1,l,l+r>>1
#define rson node<<1|1,(l+r>>1)+1,r
int f[S],caltime[S];
void pushup_seg(int node){
    segt[node]=(SS){min(segt[node<<1].l,segt[node<<1|1].l),max(segt[node<<1].r,segt[node<<1|1].r),segt[node<<1].size+segt[node<<1|1].size};
}
void build_seg(int node,int l,int r){
    //printf("build_seg(%d,%d,%d)\n",node,l,r);
    segt[node].l=inf;
    if(l!=r)build_seg(lson),build_seg(rson);
}
void update(int node,int l,int r,int x){
    if(l==r){
        if(segt[node].r)segt[node]=(SS){inf,0,0};
        else segt[node]=(SS){l,l,1};
        return;
    }
    if(x<=l+r>>1)update(lson,x);
    else update(rson,x);
    pushup_seg(node);
}
void recover(int node){
    if(caltime[segt[node].l]==node)caltime[segt[node].l]=0;
    if(caltime[segt[node].r]==node)caltime[segt[node].r]=0;
}
int query(int node,int l,int r,int qt){
    //printf("query(%d,%d,%d,%d)\n",node,l,r,qt);
    if(segt[node].r==0)return 0;
    if(caltime[segt[node].l]==0){
        caltime[segt[node].l]=node;
        f[segt[node].l]=compare(sa[segt[node].l],qt);
    }
    if(f[segt[node].l]==1){
        recover(node);
        return 0;
    }
    if(caltime[f[segt[node].r]]==0){
        caltime[segt[node].r]=node;
        f[segt[node].r]=compare(sa[segt[node].r],qt);
    }
    if(f[segt[node].r]==-1){
        recover(node);
        return 0;
    }
    if(f[segt[node].l]==0&&f[segt[node].r]==0){
        recover(node);
        return segt[node].size;
    }
    else{
        int ans=query(lson,qt)+query(rson,qt);
        recover(node);
        return ans;
    }
}

struct QS{
    int t,i;
};
vector<QS> que[S];
int ans[Q];

int cur[S];
void dfs(){
    for(int i=n;i;--i)cur[i]=ptr[i];
    for(stack[top++]=1;top--;){
        if(cur[stack[top]]==ptr[stack[top]]){
            //printf("First visit %d in the stack\n",stack[top]);
            //printf("add_seg(%d at %d)\n",stack[top],rank[stack[top]]);
            update(1,1,n,rank[stack[top]]);
            for(int i=que[stack[top]].size();i--;){
                //cout<<i<<endl;
                //printf("Get %d at %d\n",que[stack[top]][i].i,stack[top]);
                //cout<<(size[que[stack[top]][i].t]==inf||root[que[stack[top]][i].t]==0)<<endl;
                if(size[que[stack[top]][i].t]==inf||root[que[stack[top]][i].t]==0)ans[que[stack[top]][i].i]=0;
                else ans[que[stack[top]][i].i]=query(1,1,n,que[stack[top]][i].t);
            }
        }
        if(cur[stack[top]]){
            stack[top+1]=succ[cur[stack[top]]];
            //cout<<cur[stack[top]]<<"->"<<next[cur[stack[top]]]<<endl;
            cur[stack[top]]=next[cur[stack[top]]];
            top+=2;
        }
        else update(1,1,n,rank[stack[top]]);
    }
}

char * cp=(char *)malloc(5000000);
void in(int &x){
    while(*cp<'0'||*cp>'9')++cp;
    for(x=0;*cp>='0'&&*cp<='9';)x=x*10+(*cp++^'0');
}
void in(char &c){
    while(*cp<'a'||*cp>'z')++cp;
    c=*cp++;
}
int main(){
    //freopen("bzoj_2787.in","r",stdin);
    //freopen("bzoj_2787.out","w",stdout);
    fread(cp,1,5000000,stdin);

    power[0]=1;
    for(int i=1;i<=1e5+2;++i)power[i]=power[i-1]*base;

    int q;
    in(q);
    int opt;
    int u,v;
    char c;
    int ttot=2;
    for(int i=0;i<q;++i){

        //printf("---%d---\n",i);
        //if(i==200000)return 0;

        in(opt);
        switch(opt){
            case 1:
                in(u),in(c);
                a[++n]=c-'a'+1;
                addedge(u,n);
                break;
            case 2:
                in(opt),in(u),in(c);
                if(size[u]+1<inf){
                    c+=-'a'+1;
                    bst[btot]=(TS){0,0,c,rand_32(),c,1};

                    //printf("newnode:");
                    //out(btot);

                    if(opt==0){
                        merge(root[ttot],btot++,root[u]);
                        thash[ttot]=c*power[size[u]]+thash[u];
                    }
                    else{
                        merge(root[ttot],root[u],btot++);
                        thash[ttot]=thash[u]*base+c;
                    }
                }
                size[ttot++]=min(size[u]+1,inf);
                break;
            case 3:
                in(u),in(v);
                if(size[u]+size[v]<inf){
                    merge(root[ttot],root[u],root[v]);
                    thash[ttot]=thash[u]*power[size[v]]+thash[v];
                }
                size[ttot++]=min(size[u]+size[v],inf);
                break;
            case 4:
                in(u),in(v);
                que[v].push_back((QS){u,i});
                //cout<<"Add:"<<v<<endl;
                break;
        }
    }

    bfs();
    build_sa();
    build_seg(1,1,n);
    memset(ans,-1,sizeof(ans));

    //printf("root=\n");
    //for(int i=1;i<ttot;++i)printf("%d:%d\n",i,root[i]);

    //printf("shash=\n");
    //for(int i=1;i<=n;++i)printf("%d:%d\n",i,shash[i]);

    //printf("thash=\n");
    //for(int i=1;i<ttot;++i)printf("%d:%d\n",i,thash[i]);

    //puts("");

    dfs();

    for(int i=0;i<q;++i)
        if(~ans[i])
            printf("%d\n",ans[i]);
}

总结:
①ac自动机与sa很多时候能做相同的事情,如果觉得其中一个做起来困难,可以考虑另一个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值