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

     

  • 相关阅读:
    面向对象(接口 ,多态)
    面向对象(继承,重写,this,super,抽象类)
    IO(字符流 字符缓冲流)
    ArrayList集合
    字符串常用API
    面向对象(类,封装,this,构造方法)
    不同类型问题代码训练
    java中的方法
    04慕课网《进击Node.js基础(一)》HTTP讲解
    《JavaScript设计模式与开发实践》——第3章 闭包和高阶函数
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6599270.html
Copyright © 2011-2022 走看看