• bzoj3879: SvT


    题意:给一个字符串,多组查询,一些后缀两两的lcp长度和,查询个数和不超过1e6
    题解:svt就是后缀虚树,suffix virtual tree,考虑后缀树lca求lcp长度,但是查询次数可能很多,不能每次遍历,所以要建出虚数后在虚树上dp,对于一个节点考虑算贡献,对于所有子树,两两算个数乘积乘上该点的长度即可
    不会直接建后缀树= =,所以写了sam建后缀树

    /**************************************************************
        Problem: 3879
        User: walfy
        Language: C++
        Result: Accepted
        Time:28196 ms
        Memory:252900 kb
    ****************************************************************/
     
    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3)
    //#pragma GCC optimize(4)
    //#pragma GCC optimize("unroll-loops")
    //#pragma comment(linker, "/stack:200000000")
    //#pragma GCC optimize("Ofast,no-stack-protector")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define db double
    #define mp make_pair
    #define pb push_back
    #define pi acos(-1.0)
    #define ll long long
    #define vi vector<int>
    #define mod 1000000007
    #define ld long double
    #define C 0.5772156649
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define pll pair<ll,ll>
    #define pil pair<int,ll>
    #define pli pair<ll,int>
    #define pii pair<int,int>
    //#define cd complex<double>
    #define ull unsigned long long
    #define base 1000000000000000000
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define fin freopen("a.txt","r",stdin)
    #define fout freopen("b.txt","w",stdout)
    #define fio ios::sync_with_stdio(false);cin.tie(0)
    template<typename T>
    inline T const& MAX(T const &a,T const &b){return a>b?a:b;}
    template<typename T>
    inline T const& MIN(T const &a,T const &b){return a<b?a:b;}
    //inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;}
    inline void sub(ll &a,ll b){a-=b;if(a<0)a+=mod;}
    inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
    inline ll qp(ll a,ll b,ll c){ll ans=1;while(b){if(b&1)ans=ans*a%c;a=a*a%c,b>>=1;}return ans;}
     
    using namespace std;
     
    const double eps=1e-8;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    const int N=500000+10,maxn=3000000+10,inf=0x3f3f3f3f;
     
    inline int read() {
        char ch = getchar(); int x = 0, f = 1;
        while(ch < '0' || ch > '9') {
            if(ch == '-') f = -1;
            ch = getchar();
        } while('0' <= ch && ch <= '9') {
            x = x * 10 + ch - '0';
            ch = getchar();
        } return x * f;
    }
    char s[N];
    struct SAM{
        int last,cnt;
        int ch[N<<1][26],fa[N<<1],l[N<<1],pos[N<<1];
    //    bool val[N<<1];
        inline void ins(int x,int po)
        {
            int p=last,np=++cnt;last=np;l[np]=l[p]+1;
            pos[np]=po;//val[np]=1;
            for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
            if(!p)fa[np]=1;
            else
            {
                int q=ch[p][x];
                if(l[q]==l[p]+1)fa[np]=q;
                else
                {
                    int nq=++cnt;l[nq]=l[p]+1;
                    memcpy(ch[nq],ch[q],sizeof ch[q]);
                    fa[nq]=fa[q];fa[q]=fa[np]=nq;pos[nq]=pos[q];
                    for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
                }
            }
        }
        inline void build()
        {
            last=cnt=1;
            int len=strlen(s+1);
            for(int i=len;i>=1;i--)ins(s[i]-'a',i);
        }
    }sam;
    //int ra[N],sa[N],tp;
    struct suffixtree{
        int id[N<<1];
        struct edge{int to,Next;}ch[N<<1];
        int cnt,head[N<<1];
        void add(int u,int v)
        {
            ch[cnt].to=v;
            ch[cnt].Next=head[u];
            head[u]=cnt++;
        }
        inline void solve(int u)
        {
    //        if(sam.val[u])sa[ra[sam.pos[u]]=++tp]=sam.pos[u];
            for(int i=head[u];~i;i=ch[i].Next)solve(ch[i].to);
            if(!id[sam.pos[u]])id[sam.pos[u]]=u;
        }
        inline void build()
        {
            cnt=0;
            memset(head,-1,sizeof head);
            for(int i=2;i<=sam.cnt;i++)
            {
                add(sam.fa[i],i);
    //            ch[sam.fa[i]][s[sam.pos[i]+sam.l[sam.fa[i]]]-'a']=i;
            }
            solve(1);
        }
    }suf;
    int l[N<<1],deep[N<<1],res,fa[21][N<<1];
    inline bool cmp(const int &a,const int &b){return l[a]<l[b];}
    inline void dfs(int u,int dep)
    {
        l[u]=++res;deep[u]=dep;
        for(int i=suf.head[u];~i;i=suf.ch[i].Next)
            fa[0][suf.ch[i].to]=u,dfs(suf.ch[i].to,dep+1);
    }
    inline void gao()
    {
        for(int i=1;i<=20;i++)
            for(int j=1;j<=sam.cnt;j++)
                fa[i][j]=fa[i-1][fa[i-1][j]];
    }
    inline int lca(int x,int y)
    {
        if(deep[x]>deep[y])swap(x,y);
        for(int i=20;i>=0;i--)
            if(((deep[y]-deep[x])>>i)&1)
                y=fa[i][y];
        if(y==x)return x;
        for(int i=20;i>=0;i--)
        {
            if(fa[i][x]!=fa[i][y])
            {
                x=fa[i][x];
                y=fa[i][y];
            }
        }
        return fa[0][x];
    }
    int st[N<<1],top,a[maxn],sz[N<<1];
    bool vis[N<<1];
    vi in;
    struct edge{int to,Next;}e[N<<1];
    int cnt,head[N<<1];
    void init()
    {
        cnt=0;
        memset(head,-1,sizeof head);
    }
    void add(int u,int v)
    {
        e[cnt].to=v;
        e[cnt].Next=head[u];
        head[u]=cnt++;
    }
    ll ans;
    inline void add1(int a,int b){add(a,b);in.pb(a),in.pb(b);}
    inline void ins(int x)
    {
        if(!top){st[++top]=x;return ;}
        int lc=lca(st[top],x);
        while(top>1&&deep[st[top-1]]>deep[lc])
            add1(st[top-1],st[top]),top--;
        if(top>=1&&deep[st[top]]>deep[lc])
            add1(lc,st[top]),top--;
        if(!top||deep[st[top]]<deep[lc])st[++top]=lc;
        st[++top]=x;
    }
    inline void dfs1(int u)
    {
        sz[u]=0;
        for(int i=head[u];~i;i=e[i].Next)
        {
            int x=e[i].to;
            dfs1(x);
            ans+=1ll*sz[x]*sz[u]*sam.l[u];
            sz[u]+=sz[x];
        }
        if(vis[u])
        {
            ans+=1ll*sz[u]*sam.l[u];
            sz[u]++;
        }
    }
    inline void solve()
    {
        int k=read();
        for(int i=0;i<k;i++)a[i]=read(),a[i]=suf.id[a[i]];
        sort(a,a+k,cmp);
        k=unique(a,a+k)-a;
        top=0;ins(1);
        for(int i=0;i<k;i++)
        {
            vis[a[i]]=1;
            if(a[i]!=1)ins(a[i]);
        }
        while(top>=2)add1(st[top-1],st[top]),top--;
        ans=0;dfs1(1);printf("%lld
    ",ans);
        cnt=0;
        for(int i=0;i<in.size();i++)head[in[i]]=-1;
        for(int i=0;i<k;i++)vis[a[i]]=0;
        in.clear();
    }
    int main()
    {
    //    fin;fout;
        int n=read(),m=read();
        scanf("%s",s+1);
        sam.build();
        suf.build();
        dfs(1,1);gao();
        init();
        while(m--)solve();
        return 0;
    }
    /********************
    10 1
    abcdefghij
    10
    1 2 3 4 5 6 7 8 9 10
    ********************/
    
  • 相关阅读:
    CODEVS 3137 栈练习1
    CODEVS 3138 栈练习2
    线段树———模板
    深度优先搜索与广度优先搜索———模板
    犯罪团伙 codevs 3554
    嘟!数字三角形 W WW WWW集合!
    寻找子串位置 codevs 1204
    流输入练习——寻找Sb.VI codevs 3096
    C++之路进阶——codevs3287(货车运输)
    c++之路进阶——codevs4543(普通平衡树)
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/9897424.html
Copyright © 2020-2023  润新知