Address

洛谷P2336
BZOJ2754
LOJ#2374

Solution

考虑在每个人的姓和名之间插入一个无关的字符。
这样问题就转化成了一些主串和一些模式串,询问每个模式串能匹配到多少个主串,以及每个主串能匹配到多少个模式串。
把所有的主串和所有的模式串用无关字符连接起来构成一个串 SSS ,并对 SSS 串求后缀数组。
(注:上面用到的所有无关字符必须两两不同,否则会出锅)
先考虑一个弱化:判断一个模式串是否是一个主串的子串。
找到 SSS 中这个主串对应的下标集合 SAS_ASA​ ,以及模式串的开头在 SSS 中的对应下标位置 xxx ,
那么模式串是主串的子串,当且仅当存在 y∈SAy\in S_Ay∈SA​ ,
使得 LCP(S[x...∣S∣],S[y...∣S∣])≥LLCP(S[x...|S|],S[y...|S|])\ge LLCP(S[x...∣S∣],S[y...∣S∣])≥L 。其中 LLL 为模式串的长度。
众所周知, heightheightheight 数组可以将 LCPLCPLCP 转成区间最小值。
所以我们可以利用树状数组等,求出 [l,r][l,r][l,r] 表示满足 heightheightheight 的区间 [l+1,x][l+1,x][l+1,x] 和 区间 [x+1,r][x+1,r][x+1,r] 的最小值都不小于 LLL ,并且 lll 最小, rrr 最大。
那么再次转化:判断是否存在 i∈[l,r]i\in[l,r]i∈[l,r] 满足 sa[i]∈SAsa[i]\in S_Asa[i]∈SA​。
给 SSS 的每个下标一个 col[i]col[i]col[i] :如果 S[i]S[i]S[i] 来自第 kkk 个主串则 col[i]=kcol[i]=kcol[i]=k ,否则为 000 。
于是,判断一个模式串是否能匹配主串 kkk ,就转化成是否存在 i∈[l,r]i\in[l,r]i∈[l,r] 满足 col[sa[i]]=kcol[sa[i]]=kcol[sa[i]]=k 。
这样,求一个模式串能匹配多少个主串,就相当于统计一个区间内出现了多少种不同的数。
这是莫队的经典应用。
对于第二问,我们可以在莫队移动指针的过程中,维护每个数 xxx 最近一次进入区间的时间 txt_xtx​ ,然后如果在 rrr 时刻 xxx 移出了区间,则为 xxx 的答案贡献 r−txr-t_xr−tx​ 。
最后区间内还有一些数,需要为其中的每个数 xxx 的答案贡献 m−tx+1m-t_x+1m−tx​+1 。

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
#define Pow(k, n) for (k = 1; k < n; k <<= 1, std::swap(x, y))
#define Bitr(x, n) for (; x <= n; x += x & -x)
#define Bitl(x) for (; x; x -= x & -x)inline int read()
{int res = 0; bool bo = 0; char c;while (((c = getchar()) < '0' || c > '9') && c != '-');if (c == '-') bo = 1; else res = c - 48;while ((c = getchar()) >= '0' && c <= '9')res = (res << 3) + (res << 1) + (c - 48);return bo ? ~res + 1 : res;
}template <class T>
T Max(T a, T b) {return a > b ? a : b;}const int N = 5e5 + 5;int n, m, T, s[N], w[N], sa[N], rank[N], height[N], id[N],
l1, l2, pos[N], len[N], ans[N], lst[N], sna[N], A[N], S,
cnt[N], now_ans;void change(int x, int v)
{Bitr(x, T) A[x] = Max(A[x], v);
}int ask(int x)
{int res = 0;Bitl(x) res = Max(res, A[x]);return res;
}struct query
{int l, r, bl, id;
} que[N];bool comp(query a, query b)
{return a.bl < b.bl || (a.bl == b.bl && a.r < b.r);
}void build_sa(int n, int q)
{int i, k, *x = rank, *y = height, m = 0;For (i, 1, n) w[m = Max(m, s[i]), x[i] = s[i]]++;For (i, 2, m) w[i] += w[i - 1];For (i, 1, n) sa[w[x[i]]--] = i;Pow(k, n){int tt = 0;For (i, n - k + 1, n) y[++tt] = i;For (i, 1, n) if (sa[i] > k) y[++tt] = sa[i] - k;For (i, 1, m) w[i] = 0;For (i, 1, n) w[x[i]]++;For (i, 2, m) w[i] += w[i - 1];Rof (i, n, 1) sa[w[x[y[i]]]--] = y[i];m = 0;For (i, 1, n){int u = sa[i], v = sa[i - 1];y[u] = x[u] != x[v] || x[u + k] != x[v + k] ? ++m : m;}if (m == n) break;}if (y != rank) std::copy(y, y + n + 1, rank);k = 0;For (i, 1, n){if (k) k--;while (s[i + k] == s[sa[rank[i] - 1] + k]) k++;height[rank[i]] = k;}For (i, 2, n){change(height[i] + 1, i);if (pos[sa[i]]){int x = ask(len[pos[sa[i]]]);que[pos[sa[i]]].l = x ? x : 1;}}memset(A, 0, sizeof(A));Rof (i, n, 2){if (pos[sa[i]]){int x = ask(len[pos[sa[i]]]);que[pos[sa[i]]].r = x ? n - x : n;}change(height[i] + 1, n - i + 1);}S = sqrt(n);For (i, 1, q) que[i].id = i, que[i].bl = (que[i].l - 1) / S + 1;std::sort(que + 1, que + q + 1, comp);
}int main()
{int i, j;n = read(); m = read();For (i, 1, n){l1 = read();For (j, 1, l1) s[++T] = read() + 1, id[T] = i;s[++T] = 10001 + (i << 1) - 1;l2 = read();For (j, 1, l2) s[++T] = read() + 1, id[T] = i;s[++T] = 10001 + (i << 1);}For (i, 1, m){len[i] = read();pos[T + 1] = i;For (j, 1, len[i]) s[++T] = read() + 1;s[++T] = 10001 + (n << 1) + i;}build_sa(T, m);int l = 1, r = 0;For (i, 1, m){int tl = que[i].l, tr = que[i].r;while (r < tr) if (!(cnt[id[sa[++r]]]++))now_ans++, lst[id[sa[r]]] = i;while (l > tl) if (!(cnt[id[sa[--l]]]++))now_ans++, lst[id[sa[l]]] = i;while (r > tr) if (!(--cnt[id[sa[r--]]]))now_ans--, sna[id[sa[r + 1]]] += i - lst[id[sa[r + 1]]];while (l < tl) if (!(--cnt[id[sa[l++]]]))now_ans--, sna[id[sa[l - 1]]] += i - lst[id[sa[l - 1]]];ans[que[i].id] = now_ans - (cnt[0] != 0);}For (i, 1, m) printf("%d\n", ans[i]);For (i, 1, n) if (cnt[i]) sna[i] += m - lst[i] + 1;For (i, 1, n) printf("%d ", sna[i]);std::cout << std::endl;return 0;
}

[BZOJ2754][SCOI2012]喵星球上的点名(后缀数组+莫队)相关推荐

  1. [SCOI2012]喵星球上的点名(后缀数组+莫队+ST表)

    传送门 这题是真的秀.一眼看下去感觉AC自动机很可做,第一个问比较好处理,dfs序即可搞定,可第二问有点抽象,目前对树形结构的知识点不足以支持我解决这个问题.所以舍弃AC自动机,用SA做. SA做法: ...

  2. bzoj 2754 [SCOI2012]喵星球上的点名 后缀数组+莫队

    先把所有串按顺序放到一起,两个串间加非法字符隔开,求一个后缀数组. 然后对于询问,满足条件的子串在后缀数组上一定是连续一段区间. 这个区间的左右端点可以在读入的过程中二分求. 然后这个问题变成了多组询 ...

  3. [BZOJ2754][SCOI2012]喵星球上的点名 后缀数组

    不科学啊...这题暴力可过...感觉所有串都是a就可以卡掉啊... 我的做法就是先把姓名串和询问串全部连在一起,并打上分隔符,并记录每个字符属于哪个串,求出SA.对于每个询问就从它所在的位置左右扫he ...

  4. BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)

    Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...

  5. 洛谷2336 BZOJ2754 SCOI2012 喵星球上的点名 SA 莫队 二分

    题目链接 题意: 有nnn个人,每个人有两个串,一个表示姓,一个表示名,这里用数字表示字符.有mmm次询问,对于每次询问,你要回答有多少个人的姓或者名至少有一个是给出的串的子串.最后再对于这nnn个人 ...

  6. [BZOJ2754]-[SCOI2012]喵星球上的点名-AC自动机+树状数组

    说在前面 感觉这题还是挺经典的 所以还是写了记录一下- 题目 BZOJ2754传送门 洛谷P2336传送门 看题可进传送门 题目-略长,概括起来有点麻烦 解法 读完这道题之后,可以发现实际上它就是要我 ...

  7. bzoj2754: [SCOI2012]喵星球上的点名

    传送门 事实证明,我肉眼debug了两个晚上,还是不及对拍效率高. AC自动机写错了都毫不自觉的智障宸 因为数据水,写的暴力 //Achen #include<algorithm> #in ...

  8. 【BZOJ2754】[SCOI2012]喵星球上的点名

    [BZOJ2754][SCOI2012]喵星球上的点名 题面 bzoj 洛谷 题解 这题有各种神仙做法啊,什么暴力\(AC\)自动机.\(SAM\)等等五花八门 我这个蒟蒻在这里提供一种复杂度正确且常 ...

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

    二次联通门 : BZOJ 2754: [SCOI2012]喵星球上的点名 /*BZOJ 2754: [SCOI2012]喵星球上的点名此题有N种做法...见到众dalao用各种奇怪的姿势AC此题..具 ...

最新文章

  1. js 闭包 实战1
  2. 科学互驳:大脑细胞活到老,长到老?
  3. 实验三:实现一个大素数生成算法
  4. JavaScript(3)之——对象的属性描述符
  5. windows server 2012 添加中文语言包(英文转为中文)(离线)
  6. mysql数据库基本操作命令
  7. pyaudio:基于pyaudio利用Python编程从电脑端录制音频保存到指定文件夹+将录音上传服务器+录音进行识别并转为文本保存
  8. Windows下搭建PySpark环境
  9. Hi3516A开发--安装交叉编译器
  10. [.NET开发] C#连接MySQL的两个简单代码示例
  11. 开源方案搭建可离线的精美矢量切片地图服务-3.Mapbox个性化地图定制入门
  12. bootstrap算法_决策树算法之随机森林
  13. 矩阵可逆的一种刻画方式
  14. LeetCode 1670. 设计前中后队列(deque)
  15. 如何判断链表中存在环路
  16. 使用SQL向SQL Server2005中插入图片
  17. 英特尔发布P900 Optane固态盘 而主打的市场并非数据中心
  18. 中小型企业网络IP地址规划案例
  19. java wmic_强大的命令行工具wmic
  20. android 原生camera——设置模块修改

热门文章

  1. 全球各国as自治系统总数排名、全球自治系统总数排名
  2. 经纬财富:银价继续承压 今晚关注消费者指数 东莞
  3. Tobii眼动仪系列软件安装与使用
  4. c语言hid,HIDAPI首页、文档和下载 - HID 设备的 C 语言通用库
  5. 西安拟制定羊肉泡馍肉夹馍制作标准
  6. 最近听到一首挺好听的歌,但是……
  7. 根据经纬度查询,mysql查询计算经纬度
  8. 第1章 持续交付2.0
  9. 2021年全球开关收入大约4944.1百万美元,预计2028年达到6146.3百万美元
  10. 聊聊WEB项目中的图片