zoukankan      html  css  js  c++  java
  • BZOJ 2754 SCOI 2012 喵星球上的点名 后缀数组 树状数组

    2754: [SCOI2012]喵星球上的点名

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 2068  Solved: 907
    [Submit][Status][Discuss]

    Description

    a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
    现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?  

    Input

     
    现在定义喵星球上的字符串给定方法:
    先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
    输入的第一行是两个整数N和M。
    接下来有N行,每行包含第i 个喵星人的姓和名两个串。姓和名都是标准的喵星球上的
    字符串。
    接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。

    Output

     
    对于每个老师点名的串输出有多少个喵星人应该答到。
    然后在最后一行输出每个喵星人被点到多少次。

    Sample Input

    2 3
    6 8 25 0 24 14 8 6 18 0 10 20 24 0
    7 14 17 8 7 0 17 0 5 8 25 0 24 0
    4 8 25 0 24
    4 7 0 17 0
    4 17 0 8 25

    Sample Output


    2
    1
    0
    1 2
    【提示】
    事实上样例给出的数据如果翻译成地球上的语言可以这样来看
    2 3
    izayoi sakuya
    orihara izaya
    izay
    hara
    raiz

    HINT

    【数据范围】

     对于30%的数据,保证:

    1<=N,M<=1000,喵星人的名字总长不超过4000,点名串的总长不超过2000。

    对于100%的数据,保证:

    1<=N<=20000,1<=M<=50000,喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过10000。

    Solution1

    把名字和点名串用不同的字符连在一起,给对应名字的后缀打标记,做出后缀数组后,对于每个询问,找出其rank值,在sa中左右两边找,用一个数组统计答案即可。

    这个东西是很暴力的,但是,数据很水,就可以水过了。

    打的时候,把x设了值,又把x、y换了,调了很久。

    Solution2

    上面的做法是比较不稳定的,看数据,下面的做法则是稳定的O(nlogn)-----(十分感谢Semiwaker大佬的指导)。

      我们可以发现,对于一个询问,那么它在sa数组中对应了一段可行的区间,需要统计这个区间内有多少个属于不同名字的后缀。

      另外,我们也需要知道,属于同一个名字的后缀,被多少个区间所覆盖。

      对于第一个问题,我们可以利用扫描线的方法来解决。对于每个名字所对应的后缀,我们只去计算它最后的那一个。但这个要怎么搞呢?

    我们可以把所有的区间按右端点为第一关键字,左端点为第二关键字排序。假设当前遇到了一个后缀,我们就看同名字的后缀前面有没有出现过,如果没有,就直接在该位置+1;否则就把前面出现过的最后的那个后缀的位置-1,再在当前位置上+1。这个可以用一个树状数组来维护,遇到询问区间,只需要区间求和就好。

    对于第二个问题,我们依然可以利用扫描线的方法来解决。对于每个名字所对应的的后缀,我们只计算它在该询问区间中,出现的最左的那一个就好。

    我们可以把所有区间化为左端点+1、右端点-1。那么要如何统计呢?我们记录每一个名字当前出现的最迟的后缀的编号,再做一个区间求和就可以了,这个可以用树状数组来完成。

    总的时间复杂度为O(nlogn),但似乎跑得比暴力还要慢,是我写得不好吗?

    Code1

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <string>
      5 #include <algorithm>
      6 #include <iostream>
      7 #include <set>
      8 
      9 using namespace std;
     10 
     11 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
     12 #define DWN(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
     13 #define mset(a, b) memset(a, b, sizeof(a))
     14 const int maxn = 1000005;
     15 int sa[maxn], h[maxn], rk[maxn], num[maxn];
     16 int w_a[maxn], w_b[maxn], w_v[maxn], w_s[maxn];
     17 int bel[maxn];
     18 struct Node
     19 {
     20     int len, start;
     21 }d[maxn];
     22 int vis[maxn], ans[maxn];
     23 int temp[maxn], t_cnt;
     24 
     25 bool cmp(int *x, int a, int b, int l)
     26 {
     27     return x[a+l] == x[b+l] && x[a] == x[b];
     28 }
     29 
     30 void da(int n, int m)
     31 {
     32     int *x = w_a, *y = w_b, *t; t_cnt = 0;
     33     REP(i, 1, n) x[i] = num[i];
     34     REP(i, 0, m) w_s[i] = 0;
     35     REP(i, 1, n) w_s[x[i]] ++;
     36     REP(i, 1, m) w_s[i] += w_s[i-1];
     37     DWN(i, n, 1) sa[w_s[x[i]] --] = i;
     38     for (int j = 1, p = 0; p != n; m = p, j *= 2)
     39     {
     40         p = 0;
     41         REP(i, n-j+1, n)
     42             y[++p] = i;
     43         REP(i, 1, n)
     44             if (sa[i]-j > 0)
     45                 y[++p] = sa[i]-j;
     46         REP(i, 1, n) w_v[i] = x[y[i]];
     47         REP(i, 0, m) w_s[i] = 0;
     48         REP(i, 1, n) w_s[w_v[i]] ++;
     49         REP(i, 1, m) w_s[i] += w_s[i-1];
     50         DWN(i, n, 1) sa[w_s[w_v[i]] --] = y[i];
     51         p = 1, t = x, x = y, y = t, x[sa[1]] = 1; //千万注意啊,不能把交换往后挪啊 
     52         REP(i, 2, n) x[sa[i]] = cmp(y, sa[i], sa[i-1], j) ? p : ++p;
     53     }
     54 }
     55 
     56 void calc_height(int n)
     57 {
     58     REP(i, 1, n) rk[sa[i]] = i;
     59     int k = 0;
     60     REP(i, 1, n)
     61     {
     62         if (k) k --;
     63         int j = sa[rk[i]-1];
     64         while (num[i+k] == num[j+k] && i+k <= n && j+k <= n) k ++;
     65         h[rk[i]] = k;
     66     }
     67 }
     68 
     69 int main()
     70 {
     71     int len = 0, n, m, breaker = 10001;
     72     scanf("%d %d", &n, &m);
     73     REP(i, 1, n)
     74     {
     75         int l;
     76         scanf("%d", &l);
     77         REP(j, 1, l)
     78             scanf("%d", &num[++len]), bel[len] = i, num[len] ++;
     79         num[++len] = ++breaker;
     80         scanf("%d", &l);
     81         REP(j, 1, l)
     82             scanf("%d", &num[++len]), bel[len] = i, num[len] ++;
     83         num[++len] = ++breaker;
     84     }
     85     REP(i, 1, m)
     86     {
     87         scanf("%d", &d[i].len);
     88         d[i].start = len+1;
     89         REP(j, 1, d[i].len)
     90             scanf("%d", &num[++len]), num[len] ++;
     91         num[++len] = ++breaker;
     92     }
     93     da(len, breaker);
     94     calc_height(len);
     95     REP(i, 1, m)
     96     {
     97         int l = rk[d[i].start], r = rk[d[i].start], now_l = d[i].len;
     98         while (l >= 2 && min(h[l], now_l) >= d[i].len)
     99             now_l = min(now_l, h[l]), l --;
    100         now_l = len;
    101         while (r+1 <= n && min(now_l, h[r+1]) >= d[i].len)
    102             r ++, now_l = min(now_l, h[r]);
    103         int cnt = 0;
    104         REP(j, l, r)
    105             if (vis[bel[sa[j]]] != i && bel[sa[j]] != 0)
    106             {
    107                 vis[bel[sa[j]]] = i;
    108                 cnt ++;
    109                 ans[bel[sa[j]]] ++;
    110             }
    111         printf("%d
    ", cnt);
    112     }
    113     REP(i, 1, n)
    114         printf("%d%c", ans[i], i == n ? '
    ' : ' ');
    115     return 0;
    116 }
    View Code

    Code2

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <string>
      5 #include <algorithm>
      6 #include <cmath>
      7 #include <vector>
      8 
      9 using namespace std;
     10 
     11 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
     12 #define DWN(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
     13 #define mset(a, b) memset(a, b, sizeof(a))
     14 const int maxn = 300005;
     15 int n, m, bel[maxn], num[maxn];
     16 int w_a[maxn], w_b[maxn], w_v[maxn], w_s[maxn], sa[maxn], rk[maxn], h[maxn], st[maxn][21];
     17 struct Node
     18 {
     19     int len, start, l, r, id;
     20     bool operator < (const Node &AI) const { return r == AI.r ? l < AI.l : r < AI.r; }
     21 }query[maxn];
     22 int c[maxn], las[maxn], ans1[maxn], ans2[maxn], add[maxn];
     23 vector <int> del[maxn];
     24 
     25 bool cmp(int *x, int a, int b, int l) { return x[a] == x[b] && x[a+l] == x[b+l]; }
     26 
     27 void get_sa(int n, int m)
     28 {
     29     int *x = w_a, *y = w_b, *t;
     30     REP(i, 0, m) w_s[i] = 0;
     31     REP(i, 1, n) w_s[x[i]=num[i]] ++;
     32     REP(i, 1, m) w_s[i] += w_s[i-1];
     33     DWN(i, n, 1) sa[w_s[x[i]]--] = i;
     34     for (int j = 1, p = 0; p != n; j *= 2, m = p)
     35     {
     36         p = 0;
     37         REP(i, n-j+1, n) y[++p] = i;
     38         REP(i, 1, n) if (sa[i]-j > 0) y[++p] = sa[i]-j;
     39         REP(i, 1, n) w_v[i] = x[y[i]];
     40         REP(i, 0, m) w_s[i] = 0;
     41         REP(i, 1, n) w_s[w_v[i]] ++;
     42         REP(i, 1, m) w_s[i] += w_s[i-1];
     43         DWN(i, n, 1) sa[w_s[w_v[i]]--] = y[i];
     44         t = x, x = y, y = t, p = 1, x[sa[1]] = 1;
     45         REP(i, 2, n) x[sa[i]] = cmp(y, sa[i], sa[i-1], j) ? p : ++p;
     46     }
     47 }
     48 
     49 void get_h(int n)
     50 {
     51     REP(i, 1, n) rk[sa[i]] = i;
     52     int k = 0;
     53     REP(i, 1, n)
     54     {
     55         if (k) k --;
     56         int j = sa[rk[i]-1];
     57         while (num[i+k] == num[j+k] && i+k <= n && j+k <= n) k ++;
     58         h[rk[i]] = k;
     59     }
     60     REP(i, 1, n) st[i][0] = h[i];
     61     REP(j, 1, 20)
     62         REP(i, 1, n)
     63             if (i+(1<<(j-1)) <= n)//必须判断,不然会RE 
     64                 st[i][j] = min(st[i][j-1], st[i+(1<<(j-1))][j-1]);
     65 }
     66 
     67 int calc(int l, int r)
     68 {
     69     l ++;
     70     int k = int(log2(r-l+1));
     71     return min(st[l][k], st[r-(1<<k)+1][k]);
     72 }
     73 
     74 int lowbit(int x) { return x & -x; }
     75 
     76 void c_modify(const int &n, int x, int d) { while (x <= n) c[x] += d, x += lowbit(x); }
     77 
     78 int c_query(const int &n, int x)
     79 {
     80     int ret = 0;
     81     while (x > 0) ret += c[x], x -= lowbit(x);
     82     return ret;
     83 }
     84 
     85 int main()
     86 {
     87     scanf("%d %d", &n, &m);
     88     int breaker = 10000, len = 0;
     89     REP(i, 1, n)
     90     {
     91         int l;
     92         scanf("%d", &l);
     93         REP(j, 1, l) scanf("%d", &num[++len]), bel[len] = i, num[len] ++;
     94         num[++len] = ++breaker;
     95         scanf("%d", &l);
     96         REP(j, 1, l) scanf("%d", &num[++len]), bel[len] = i, num[len] ++;
     97         num[++len] = ++breaker;
     98     }
     99     REP(i, 1, m)
    100     {
    101         scanf("%d", &query[i].len), query[i].id = i;
    102         query[i].start = len+1;
    103         REP(j, 1, query[i].len) scanf("%d", &num[++len]), num[len] ++;
    104         num[++len] = ++breaker;
    105     }
    106     get_sa(len, breaker), get_h(len);
    107     REP(i, 1, m)
    108     {
    109         int k = rk[query[i].start], l = 1, r = k;
    110         query[i].l = query[i].r = k;
    111         while (l <= r)
    112         {
    113             int mid = (l+r)>>1;
    114             if (calc(mid, k) >= query[i].len) query[i].l = mid, r = mid-1;    
    115             else l = mid+1;
    116         }
    117         l = k+1, r = len;
    118         while (l <= r)
    119         {
    120             int mid = (l+r)>>1;
    121             if (calc(k, mid) >= query[i].len) query[i].r = mid, l = mid+1;
    122             else r = mid-1;
    123         }
    124     }
    125     sort(query+1, query+m+1);
    126     int now = 1;
    127     REP(i, 1, len)
    128     {
    129         int k = sa[i];
    130         if (bel[k] != 0)
    131         {
    132             if (las[bel[k]] != 0) c_modify(len, las[bel[k]], -1);
    133             las[bel[k]] = i, c_modify(len, i, 1);
    134         }
    135         while (query[now].r == i && now <= m)
    136             ans1[query[now].id] = c_query(len, i)-c_query(len, query[now].l-1), now ++;
    137     }
    138     mset(c, 0), mset(las, 0);
    139     REP(i, 1, m) add[query[i].l] ++, del[query[i].r+1].push_back(query[i].l);
    140     REP(i, 1, len)
    141     {
    142         int k = sa[i];
    143         c_modify(len, i, add[i]);
    144         REP(j, 0, del[i].size()-1) c_modify(len, del[i][j], -1);//这段尤为注意,必须一边做一边删
    145         //否则,就会出现减出负数的情况 
    146         if (bel[k] != 0)
    147         {
    148             if (las[bel[k]] != 0) ans2[bel[k]] -= c_query(len, las[bel[k]]);
    149             ans2[bel[k]] += c_query(len, i), las[bel[k]] = i;
    150         }
    151     } 
    152     REP(i, 1, m) printf("%d
    ", ans1[i]);
    153     REP(i, 1, n) printf("%d%c", ans2[i], i == n ? '
    ' : ' ');
    154     return 0;
    155 }
    View Code

     

  • 相关阅读:
    LeetCode 121. Best Time to Buy and Sell Stock
    LeetCode 221. Maximal Square
    LeetCode 152. Maximum Product Subarray
    LeetCode 53. Maximum Subarray
    LeetCode 91. Decode Ways
    LeetCode 64. Minimum Path Sum
    LeetCode 264. Ugly Number II
    LeetCode 263. Ugly Number
    LeetCode 50. Pow(x, n)
    LeetCode 279. Perfect Squares
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6599270.html
Copyright © 2011-2022 走看看