zoukankan      html  css  js  c++  java
  • bzoj4199: [Noi2015]品酒大会 (并查集 && 后缀数组)

    据说用后缀自动机 + dp也能做

    然而并不会

    后缀数组的做法呢

    就是先建个后缀数组,求出height值,此时如果直接找,复杂度是n ^ 2的,肯定会超时。

    但是height大的值是不会对小的产生影响的,所以可以按height大小,从大到小合并两个区间,用并查集维护就可以了

    代码如下

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstring>
     4 using namespace std;
     5 const int N = 300010;
     6 typedef long long ll;
     7 char s[N];
     8 ll a[N];
     9 int n;
    10 int sa[N], c[N], x[N], y[N];
    11 
    12 struct E {
    13     int h, l, r;
    14     inline bool operator < (const E o) const {
    15         return h > o.h;
    16     }
    17 } g[N];
    18 inline void BuildSa(int m) {
    19     for (int i = 0; i < m; i++)    c[i] = 0;
    20     for (int i = 0; i < n; i++)    c[x[i] = s[i]]++;
    21     for (int i = 1; i < m; i++)    c[i] += c[i - 1];
    22     for (int i = n - 1; i >= 0; i--)    sa[--c[x[i]]] = i;
    23     for (int k = 1; k <= n; k <<= 1) {
    24         int p = 0;
    25         for (int i = n - k; i < n; i++)    y[p++] = i;
    26         for (int i = 0; i < n; i++)    if (sa[i] >= k)    y[p++] = sa[i] - k;
    27         for (int i = 0; i < m; i++)    c[i] = 0;
    28         for (int i = 0; i < n; i++)    c[x[y[i]]]++;
    29         for (int i = 1; i < m; i++)    c[i] += c[i - 1];
    30         for (int i = n - 1; i >= 0; i--)    sa[--c[x[y[i]]]] = y[i];
    31         p = 1; swap(x, y);
    32         x[sa[0]] = 0;
    33         for (int i = 1; i < n; i++)
    34             x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++;
    35         if (p >= n)    break;
    36         m = p;
    37     }
    38 }
    39 
    40 int height[N], rank[N];
    41 inline void GetHeight() {
    42     for (int i = 0; i < n; i++)    rank[sa[i]] = i;
    43     int k = 0;
    44     for (int i = 0; i < n; i++) {
    45         if (k)    k--;
    46         int j = sa[rank[i] - 1];
    47         while (s[j + k] == s[i + k])    k++;
    48         height[rank[i]] = k;
    49     }
    50 }
    51 
    52 ll fa[N], size[N], ans[N], ans1[N], ans2[N], minn[N], maxn[N];
    53 void Union(int x, int y) {
    54     fa[x] = y;
    55     size[y] += size[x];
    56     ans[y] = max(ans[y], max(maxn[y] * maxn[x], minn[y] * minn[x]));
    57     maxn[y] = max(maxn[y], maxn[x]);
    58     minn[y] = min(minn[y], minn[x]);
    59 }
    60 
    61 int find(int x) {
    62     return (fa[x] == x) ? x : find(fa[x]);
    63 }
    64 
    65 int main() {
    66     scanf("%d", &n);
    67     getchar();
    68     for (int i = 0; i < n; i++)
    69         scanf("%c", &s[i]), s[i] -= 'a' - 1;
    70     for (int i = 0; i < n; i++)
    71         scanf("%lld", &a[i]);
    72     s[n++] = 0;
    73     BuildSa(30);
    74     GetHeight();
    75     for (int i = 2; i < n; i++) {
    76         g[i].h = height[i];
    77         g[i].l = sa[i];
    78         g[i].r = sa[i - 1];
    79     }
    80     sort(g + 2, g + n);
    81     for (int i = 0; i < n; i++)    fa[i] = i, size[i] = 1, maxn[i] = a[i], minn[i] = a[i];
    82     memset(ans, 0x80, sizeof(ans));
    83     memset(ans2, 0x80, sizeof(ans2));
    84     for (int i = 2; i < n; i++) {
    85         int x = find(g[i].l); 
    86         int y = find(g[i].r);
    87         ans1[g[i].h] += (ll)size[x] * size[y];
    88         Union(x, y); 
    89         ans2[g[i].h] = max(ans2[g[i].h], ans[y]);
    90     }
    91     for (int i = n - 3; i >= 0; i--) {
    92         ans1[i] += ans1[i + 1];
    93         if (ans1[i + 1])    ans2[i] = max(ans2[i], ans2[i + 1]);
    94     }
    95     for (int i = 0; i < n - 1; i++)    printf("%lld %lld
    ", ans1[i], ans1[i] ? ans2[i] : 0);
    96     return 0;
    97 }
  • 相关阅读:
    【五校联考5day1】登山
    非旋Treap及其可持久化
    自然数幂求和——第二类Strling数
    [JZOJ6011] 【NOIP2019模拟1.25A组】天天爱跑步
    [JZOJ5232] 【NOIP2017模拟A组模拟8.5】带权排序
    FreeRTOS 任务通知模拟消息邮箱
    Python爬虫技术:爬虫时如何知道是否代理ip伪装成功?
    Python网络爬虫入门实战(爬取最近7天的天气以及最高/最低气温)
    Python numpy的基本操作你一般人都不会
    如何正确的使用Python解释器?你之前肯定用错了
  • 原文地址:https://www.cnblogs.com/cminus/p/8458200.html
Copyright © 2011-2022 走看看