zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第六场)C:Palindrome Mouse(回文树+树剖)

    题意:给定字符串Str,求出回文串集合为S,问S中的(a,b)满足a是b的子串的对数。

    思路:开始和题解的思路差不多,维护当前后缀的每个串的最后出现位置,但是不知道怎么套“最小回文分割”,所以想到了树剖,但是树剖不好同时维护“最后出现的次数”,“查询左端点>=L”的位置数。   所以GG。  那么从图论的角度考虑,有向图,问多少个点可以到达的关系点对,(我怎么只会bitset解决小数据问题)。

    1,而回文树的特殊性在于,每个点只有一个fail(回边),25个next(出边),那么把回边抽离出来建立fail树。那么就是顺着next可以得到答案,问题是要去重。

    去重的过程可以加一个vis数组标记即可。  这种有向图,DFS可做。

    2,这里为了和比赛的时候想法接近一下,是用树剖实现的。  fail树上树剖,next指针搜索,每次把当前点的fail链标记量++;  回溯的时候标记量--;由于都是先加后删,所以没必要下推tag,这样反而保证了复杂度。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    int tot;  struct PAT
    {
        struct node{
            int len,num,fail,son[26];
        }t[maxn];
        int last,n,s[maxn];
        void init()
        {
            memset(t,0,sizeof(t));
            tot=last=1; n=0;
            t[0].len=0; t[1].len=-1;
            t[0].fail=t[1].fail=1;
            s[0]=-1;
        }
        int add(int c){
            int p=last; s[++n]=c;
            while(s[n]!=s[n-1-t[p].len]) p=t[p].fail;
            if(!t[p].son[c]){
                int v=++tot,k=t[p].fail;
                while(s[n]!=s[n-t[k].len-1]) k=t[k].fail;
                t[v].fail=t[k].son[c];
                t[v].len=t[p].len+2;
                t[v].num=t[t[v].fail].num+1;
                t[p].son[c]=v;
            }
            last=t[p].son[c];
            return t[last].num;
        }
    }T;
    char c[maxn];
    int Laxt[maxn],Next[maxn],To[maxn],cnt;
    int son[maxn],Top[maxn],fa[maxn],pos[maxn],times;
    int tag[maxn<<2],sum[maxn<<2],sz[maxn];
    void Add(int u,int v)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v;
    }
    void dfs1(int u,int f)
    {
        sz[u]=1; son[u]=0; fa[u]=f;
        for(int i=Laxt[u];i;i=Next[i]){
            if(To[i]!=f){
                dfs1(To[i],u);
                sz[u]+=sz[To[i]];
                if(sz[To[i]]>sz[son[u]]) son[u]=To[i];
            }
        }
    }
    void dfs2(int u,int tp)
    {
        Top[u]=tp; pos[u]=++times;
        if(son[u]) dfs2(son[u],tp);
        for(int i=Laxt[u];i;i=Next[i]){
            if(To[i]==son[u]) continue;
            dfs2(To[i],To[i]);
        }
    }
    void pushup(int Now,int L,int R)
    {
        if(tag[Now]) sum[Now]=R-L+1;
        else if(L==R) sum[Now]=0;
        else sum[Now]=sum[Now<<1]+sum[Now<<1|1];
    }
    void add(int Now,int L,int R,int l,int r,int x)
    {
        if(l<=L&&r>=R) {
            tag[Now]+=x;
            pushup(Now,L,R);
            return ;
        }
        int Mid=(L+R)>>1;
        if(l<=Mid) add(Now<<1,L,Mid,l,r,x);
        if(r>Mid) add(Now<<1|1,Mid+1,R,l,r,x);
        pushup(Now,L,R);
    }
    int query(int Now,int L,int R,int l,int r)
    {
        if(l<=L&&r>=R){
            if(tag[Now]) return R-L+1;
            if(L==R) return 0;
            return sum[Now<<1]+sum[Now<<1|1];
        }
        int res=0,Mid=(L+R)>>1;
        if(l<=Mid) res+=query(Now<<1,L,Mid,l,r);
        if(r>Mid) res+=query(Now<<1|1,Mid+1,R,l,r);
        pushup(Now,L,R);
        return res;
    }
    void ADD(int p,int x)
    {
        while(Top[p]!=1) {
            add(1,1,tot,pos[Top[p]],pos[p],x);
            p=T.t[Top[p]].fail;
        }
        if(p!=1) add(1,1,tot,2,pos[p],x);
    }
    long long ans;
    void solve(int u)
    {
        if(u>1) ADD(u,1),ans+=sum[1]-1;
        rep(i,0,25)
          if(T.t[u].son[i])
            solve(T.t[u].son[i]);
        if(u>1) ADD(u,-1);
    }
    int main()
    {
        int TT,C=0,N;
        scanf("%d",&TT);
        while(TT--){
            T.init(); ans=0; times=0;
            scanf("%s",c+1); N=strlen(c+1);
            rep(i,1,N) T.add(c[i]-'a');
            rep(i,1,tot) Laxt[i]=0; cnt=0;
            rep(i,2,tot) {
                if(T.t[i].fail==0) T.t[i].fail=1;
                Add(T.t[i].fail,i);
            }
            dfs1(1,0); dfs2(1,1);
            solve(1);
            solve(0);
            printf("Case #%d: %lld
    ",++C,ans);
        }
        return 0;
    }
  • 相关阅读:
    即使年龄小,我也是你的领导
    当老外骂你时,你就这样...
    纵横职场宝典
    22岁女老总欲筹办创业联盟
    让你的发言语出惊人
    爱因斯坦难题,98%的人答不出这道题!
    小本创业的11个步骤
    未来十大热门挣钱职业
    常用英语对话
    折腾是检验人才的唯一标准
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11306273.html
Copyright © 2011-2022 走看看