zoukankan      html  css  js  c++  java
  • [BZOJ3879] SvT

    Description

    给定一个长为 (n) 的串和 (m) 次询问,每次询问 (t) 个后缀之间两两LCP。(nleq 5cdot 10^5,sum tleq 3cdot 10^6)

    Solution

    就是求出来SA,然后把给定的 (t) 个串按照 (rk) 排序。求出相邻两个LCP -> 求出序列间两两最小值 -> 考虑贡献,对于每个数求是哪些数对的最小值 -> 求每个数左边右边第一个比它小的数 -> 单调栈。

    woc好牛逼

    Code

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using std::min;
    using std::max;
    using std::swap;
    using std::vector;
    typedef double db;
    typedef long long ll;
    #define pb(A) push_back(A)
    #define pii std::pair<int,int>
    #define all(A) A.begin(),A.end()
    #define mp(A,B) std::make_pair(A,B)
    const int N=5e5+5;
    
    char s[N];
    int l[N],r[N];
    int stk[N],val[N],top;
    int n,m,lg[N],st[N][20];
    int rk[N],height[N],sa[N];
    int x[N],y[N],c[N],a[N*10];
    
    bool cmp(int x,int y){
        return rk[x]<rk[y];
    }
    
    void gs(int num=0,int m=150){
        for(int i=1;i<=n;i++) c[x[i]=s[i]]++;
        for(int i=1;i<=m;i++) c[i]+=c[i-1];
        for(int i=n;i;i--) sa[c[x[i]]--]=i;
        for(int k=1;num=0,k<=n;k<<=1){
            for(int i=n-k+1;i<=n;i++) y[++num]=i;
            for(int i=1;i<=n;i++) if(sa[i]>k) y[++num]=sa[i]-k;
            for(int i=1;i<=m;i++) c[i]=0;
            for(int i=1;i<=n;i++) c[x[i]]++;
            for(int i=1;i<=m;i++) c[i]+=c[i-1];
            for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
            swap(x,y);num=x[sa[1]]=1;
            for(int i=2;i<=n;i++) x[sa[i]]=y[sa[i]]==y[sa[i-1]] and y[sa[i]+k]==y[sa[i-1]+k]?num:++num;
            if(num==n) return;m=num;
        }
    }
    
    void gh(int k=0){
        for(int i=1;i<=n;i++) rk[sa[i]]=i;
        for(int i=1;i<=n;i++){
            if(rk[i]==1) continue;
            if(k) k--;
            int j=sa[rk[i]-1];
            while(i+k<=n and j+k<=n and s[i+k]==s[j+k]) k++;
            height[rk[i]]=k;
        }
    }
    
    void gt(){
        for(int i=2;i<=n;i++) lg[i]=lg[i-1]+((1<<lg[i-1]+1)==i);
        for(int i=1;i<=n;i++) st[i][0]=height[i];
        for(int i=1;i<=lg[n];i++)
            for(int j=1;j+(1<<i)-1<=n;j++)
                st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
    }
    
    int query(int x,int y){
        if(x==y) return n-sa[x]+1;
        if(x>y) swap(x,y);x++;
        int k=lg[y-x+1];
        return min(st[x][k],st[y-(1<<k)+1][k]);
    }
    
    int getint(){
        int X=0,w=0;char ch=getchar();
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }
    
    signed main(){
        n=getint(),m=getint();
        scanf("%s",s+1);
        gs(),gh(),gt();
        while(m--){
            int len=getint();ll ans=0;
            for(int i=1;i<=len;i++) a[i]=getint();
            std::sort(a+1,a+1+len,cmp);len=std::unique(a+1,a+1+len)-a-1;
            for(int i=1;i<len;i++) val[i]=query(rk[a[i]],rk[a[i+1]]);
            for(int i=1;i<len;i++){
                while(top and val[stk[top]]>=val[i]) r[stk[top--]]=i;
                stk[++top]=i;
            } while(top) r[stk[top--]]=len;
            for(int i=len-1;i;i--){
                while(top and val[stk[top]]>val[i]) l[stk[top--]]=i;
                stk[++top]=i;
            } while(top) l[stk[top--]]=0;
            for(int i=1;i<len;i++)
                ans+=1ll*val[i]*(i-l[i])*(r[i]-i);
            printf("%lld
    ",ans);
        } return 0;
    }
    
    
  • 相关阅读:
    实现websocket中遇到的恶心问题。
    移动js框架使用报告
    超级难用的wireshark。
    三国演义LBS 20110406 本次清明节解决问题列表。
    【原创意】一个市值估算超亿的创意——愤怒的小猪(谢绝抄袭和冒名顶替)
    一个小游戏 让你感受“如何等待成功”!
    js 游戏引擎 + canvas 入门
    javascript 中的反射
    使用HTML5进行地理位置定位。误差在+500m
    【原创意】新浪微博都感到巨大鸭梨的全新创意 —— 二维码社区"神码"
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/10301269.html
Copyright © 2011-2022 走看看