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\n", cnt);
112     }
113     REP(i, 1, n)
114         printf("%d%c", ans[i], i == n ? '\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\n", ans1[i]);
153     REP(i, 1, n) printf("%d%c", ans2[i], i == n ? '\n' : ' ');
154     return 0;
155 }
View Code

 

 

posted @ 2017-03-22 12:51  Splay  阅读(304)  评论(0编辑  收藏  举报