zoukankan      html  css  js  c++  java
  • [后缀数组][并查集] Luogu P2178 品酒大会

    题解

    • 我们可以考虑从大到小枚举height,然后按顺序每一次将其两边的后缀集合合并,用并查集实现
    • 这样我们每一次合并的后缀集合的组合一定满足它们的lcp会大于等于height[i],这两个集合的合并对任意r<= h[i]的答案都有其大小乘积的贡献
    • 最大值同样维护即可,注意由于可能有负数,所以可以再维护一个最小值

     代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #define ll long long
     5 using namespace std;
     6 const ll N=300010,inf=5e18;
     7 ll n,t[N],t2[N],sa[N],rank[N],height[N],c[N],a[N],fa[N],cnt[N],mx[N],Mx[N],Mn[N],size[N];
     8 char s[N];
     9 bool cmp(ll x,ll y) { return height[x]>height[y]; }
    10 ll find(ll x) { return fa[x]==x?x:fa[x]=find(fa[x]); }
    11 void get_SA()
    12 {
    13     ll l='z',*x=t,*y=t2;
    14     for (ll i=0;i<=l;i++) c[i]=0;
    15     for (ll i=1;i<=n;i++) c[x[i]=s[i]]++;
    16     for (ll i=1;i<=l;i++) c[i]+=c[i-1];
    17     for (ll i=n;i>=1;i--) sa[c[x[i]]--]=i;
    18     for (ll k=1;k<n;k<<=1)
    19     {
    20         ll p=0;
    21         for (ll i=n-k+1;i<=n;i++) y[++p]=i;
    22         for (ll i=1;i<=n;i++)if(sa[i]>k) y[++p]=sa[i]-k;
    23         for (ll i=0;i<=l;i++) c[i]=0;
    24         for (ll i=1;i<=n;i++) c[x[y[i]]]++;
    25         for (ll i=1;i<=l;i++) c[i]+=c[i-1];
    26         for (ll i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i];
    27         swap(x,y),p=x[sa[1]]=1;
    28         for (ll i=2;i<=n;i++) x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;
    29         if (p>=n) break;
    30         l=p;
    31     }
    32     for (ll i=1;i<=n;i++) rank[sa[i]]=i;
    33     ll k=0;
    34     for (ll i=1;i<=n;i++)
    35     {
    36         ll j=sa[rank[i]+1];
    37         if (!j) continue;
    38         if (k) k--;
    39         while (s[i+k]==s[j+k]) k++;
    40         height[rank[i]]=k;
    41     }
    42     for (ll i=1;i<=n;i++) a[i]=i;
    43     sort(a+1,a+n,cmp);
    44 }
    45 int main()
    46 {
    47     scanf("%lld",&n); for (ll i=0;i<=n;i++) fa[i]=i;
    48     scanf("%s",s+1),get_SA();
    49     for (ll i=1;i<=n;i++) scanf("%lld",&Mx[rank[i]]),size[rank[i]]=1,mx[i-1]=-inf,Mn[rank[i]]=Mx[rank[i]];
    50     for (ll i=1;i<n;i++)
    51     {
    52         ll x=find(a[i]),y=find(a[i]+1);
    53         cnt[height[a[i]]]+=size[x]*size[y],mx[height[a[i]]]=max(mx[height[a[i]]],max(Mn[x]*Mn[y],Mx[x]*Mx[y])),Mn[x]=min(Mn[x],Mn[y]),Mx[x]=max(Mx[x],Mx[y]),size[x]+=size[y],fa[y]=x;
    54     }
    55     for (ll i=n-2;i>=0;i--) cnt[i]+=cnt[i+1],mx[i]=max(mx[i],mx[i+1]);
    56     for (ll i=0;i<n;i++) printf("%lld %lld
    ",cnt[i],cnt[i]?mx[i]:0);
    57 }
  • 相关阅读:
    编写安全有效的 C# 代码
    模式匹配
    C#新特性
    转 C# .NET4.0 混合模式程序集异常
    win7 64位系统 注册 ocx控件
    TIFF图像文件格式详解
    GDALOGR读取数据示例 C#版本
    使用gdal C#封装库读取DEM数据
    编译C#环境下GDAL(支持HDF4、NetCDF)
    UML类图符号 各种关系说明以及举例
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11321850.html
Copyright © 2011-2022 走看看