BZOJ 4545: DQS的trie

10 篇文章 0 订阅
4 篇文章 0 订阅

一道后缀自动机的好题,综合了后缀自动机一些重要的操作。
对于询问一,我们边建树边维护。
对于询问三,我们用一个LCT来维护。
(记得开long longQAQ)

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
struct splay
{
    splay *fa,*ls,*rs;
    int add_mark,val;
    splay(int);
    void push_down();
    void add(int v);
}*null=new splay(0);
splay :: splay(int _=0)
{
    fa=ls=rs=null;
    add_mark=0;
    val=_;
}
void splay :: add(int v)
{
    val+=v;
    add_mark+=v;
}
void splay :: push_down()
{
    if(add_mark)
    {
        if(ls!=null) ls->add(add_mark);
        if(rs!=null) rs->add(add_mark);
        add_mark=0;
    }
}
void right(splay *x)
{
    splay *y=x->fa;
    y->ls=x->rs;
    x->rs->fa=y;
    x->fa=y->fa;
    x->rs=y;
    if(y==y->fa->ls) y->fa->ls=x;
    else if(y==y->fa->rs) y->fa->rs=x;
    y->fa=x;
}
void left(splay *x)
{
    splay *y=x->fa;
    y->rs=x->ls;
    x->ls->fa=y;
    x->fa=y->fa;
    x->ls=y;
    if(y==y->fa->ls) y->fa->ls=x;
    else if(y==y->fa->rs) y->fa->rs=x;
    y->fa=x;
}
void push_down(splay *x)
{
    if(x==x->fa->ls || x==x->fa->rs) push_down(x->fa);
    x->push_down();
}
void splaying(splay *x)
{
    push_down(x);
    while(1)
    {
        splay *y=x->fa;
        splay *z=y->fa;
        if(x!=y->ls && x!=y->rs) break;
        if(y!=z->ls && y!=z->rs)
        {
            if(x==y->ls) right(x);
            else left(x);
            break;
        }
        if(x==y->ls)
        {
            if(y==z->ls) right(y);
            right(x);
        }
        else if(x==y->rs)
        {
            if(y==z->rs) left(y);
            left(x);
        }
    }
}
void access(splay *x)
{
    splay *y=null;
    while(x!=null)
    {
        splaying(x);
        x->rs=y;
        y=x;
        x=x->fa;
    }
}
void cut(splay *x)
{
    access(x);
    splaying(x);
    x->ls->fa=null;
    x->ls=null;
}
void link(splay *x,splay *y)
{
    cut(x);
    x->fa=y;
}
struct sam
{
    sam *parent,*son[26];
    int max_len;
    splay *tree;
    sam(int _=0):parent(0x0),max_len(_)
    {
        memset(son,0,sizeof(son));
        tree=new splay(0);
    }
}*root=new sam,*mempool[1000000];
long long ans=0;
sam* my_insert(sam *p,int x)
{
    /*if(p->son[x] && p->son[x]->max_len==p->max_len+1)
    {
        p->son[x]->tree->val++;
        return p->son[x];
    }*/
    sam *np=new sam(p->max_len+1);
    while(p && !p->son[x])
    {
        p->son[x]=np;
        p=p->parent;
    }
    if(!p)
    {
        np->parent=root;
        link(np->tree,root->tree);
    }
    else
    {
        sam *q=p->son[x];
        if(p->max_len==q->max_len-1)
        {
            np->parent=q;
            link(np->tree,q->tree);
        }
        else
        {
            sam *nq=new sam(p->max_len+1);
            nq->parent=q->parent;
            ans-=q->max_len-q->parent->max_len;
            link(nq->tree,q->parent->tree);
            memcpy(nq->son,q->son,sizeof(nq->son));
            q->parent=nq;np->parent=nq;
            ans+=q->max_len-q->parent->max_len;
            ans+=nq->max_len-nq->parent->max_len;
            link(q->tree,nq->tree);
            link(np->tree,nq->tree);
            push_down(q->tree);
            nq->tree->val=q->tree->val;
            while(p && p->son[x]==q)
            {
                p->son[x]=nq;
                p=p->parent;
            }
        }
    }
    ans+=np->max_len-np->parent->max_len;
    access(np->tree);
    splaying(np->tree);
    np->tree->add(1);
    return np;
}
char s[1000000];
struct bian
{
    int l,r,v;
}a[1000000];
int tot=0;
int fir[1000000];
int firc[1000000];
int nex[1000000];
int nexc[1000000];
void add_edge(int l,int r,char c,int cloc)
{
    a[++tot].l=l;
    a[tot].r=r;
    a[tot].v=c;
    if(firc[l]!=cloc)
    {
        firc[l]=cloc;
        fir[l]=0;
    }
    if(nexc[tot]!=cloc)
    {
        nex[tot]=0;
        nexc[tot]=cloc;
    }
    nex[tot]=fir[l];
    fir[l]=tot;
}
void dfs(int u,int from,int v)
{
    if(from!=0) mempool[u]=my_insert(mempool[from],v-'a');
    for(int o=fir[u];o!=0;o=nex[o])
    {
        //cout<<a[o].r<<" ";
        if(a[o].r!=from) dfs(a[o].r,u,a[o].v);
    }
}
int search_ans()
{
    sam *o=mempool[1];
    for(int i=0;s[i];i++)
    {
        if(!o->son[s[i]-'a']) return 0;
        o=o->son[s[i]-'a'];
    }
    push_down(o->tree);
    return o->tree->val;
}
int main()
{
    int id;
    scanf("%d",&id);
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int l,r;
        char c[5];
        scanf("%d%d%s",&l,&r,c);
        add_edge(l,r,c[0],0);
        add_edge(r,l,c[0],0);
    }
    mempool[1]=root;
    dfs(1,0,0);
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int opt;
        scanf("%d",&opt);
        if(opt==1) printf("%lld\n",ans);
        if(opt==2)
        {
            int rt,si;
            scanf("%d%d",&rt,&si);
            tot=0;
            for(int j=1;j<si;j++)
            {
                int l,r;
                char c[5];
                scanf("%d%d%s",&l,&r,c);
                add_edge(l,r,c[0],i);
                add_edge(r,l,c[0],i);
            }
            dfs(rt,0,0);
        }
        if(opt==3)
        {
            scanf("%s",s);
            printf("%d\n",search_ans());
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值