bzoj3879: SvT

Posted acjiumeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
********************/

以上是关于bzoj3879: SvT的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3879: SvT

bzoj3879 SvT

zoj千题计划312:bzoj3879: SvT(后缀数组+st表+单调栈)

bzoj3879

Educational Codeforces Round 53 (Rated for Div. 2)G. Yet Another LCP Problem

HDU 3879:Base Station(最大权闭合图)