bzoj 3473 字符串 - 后缀数组 - 树状数组
先用奇怪的字符把所有字符串连接起来。
建后缀树,数每个节点的子树内包含多少属于不同串的后缀。
数这个东西,可以将每个串的后缀(被奇怪的字符分割开的地方认为它属于不同后缀)按dfs序排序,然后简单容斥就能统计出来。
对于每个后缀,有贡献的是一个前缀,然后直接统计就行了。
Code
- /**
- * bzoj
- * Problem#3473
- * Accepted
- * Time: 788ms
- * Memory: 41208k
- */
- #include <iostream>
- #include <cstdlib>
- #include <cstring>
- #include <cstdio>
- #include <vector>
- #include <cmath>
- using namespace std;
- typedef bool boolean;
- template <typename T>
- void pfill(T* pst, const T* ped, T val) {
- for ( ; pst != ped; *(pst++) = val);
- }
- const int N = 2e5 + ;
- const int bzmax = ;
- typedef class SparseTable {
- public:
- int n;
- int *ar;
- int log2[N];
- int f[N][bzmax];
- SparseTable() { }
- void init(int n, int* ar) {
- this->n = n;
- this->ar = ar;
- log2[] = ;
- for (int i = ; i <= n; i++)
- log2[i] = log2[i >> ] + ;
- for (int i = ; i < n; i++)
- f[i][] = ar[i];
- for (int j = ; j < bzmax; j++)
- for (int i = ; i + ( << j) - < n; i++)
- f[i][j] = min(f[i][j - ], f[i + ( << (j - ))][j - ]);
- }
- int query(int l, int r) {
- int d = log2[r - l + ];
- // int rt = min(f[l][d], f[r - (1 << d) + 1][d]);
- // cerr << l << " " << r << " " << rt << '\n';
- return min(f[l][d], f[r - ( << d) + ][d]);
- }
- }SparseTable;
- typedef class Pair3 {
- public:
- int x, y, id;
- Pair3() { }
- Pair3(int x, int y, int id):x(x), y(y), id(id) { }
- }Pair3;
- typedef class SuffixArray {
- protected:
- Pair3 T1[N], T2[N];
- int cnt[N];
- public:
- int n;
- char *str;
- int sa[N], rk[N], hei[N];
- SparseTable st;
- void set(int n, char* str) {
- this->n = n;
- this->str = str;
- memset(sa, , sizeof(sa));
- memset(rk, , sizeof(rk));
- memset(hei, , sizeof(hei));
- }
- void radix_sort(Pair3* x, Pair3* y) {
- int m = max(n, );
- memset(cnt, , sizeof(int) * m);
- for (int i = ; i < n; i++)
- cnt[x[i].y]++;
- for (int i = ; i < m; i++)
- cnt[i] += cnt[i - ];
- for (int i = ; i < n; i++)
- y[--cnt[x[i].y]] = x[i];
- memset(cnt, , sizeof(int) * m);
- for (int i = ; i < n; i++)
- cnt[y[i].x]++;
- for (int i = ; i < m; i++)
- cnt[i] += cnt[i - ];
- for (int i = n - ; ~i; i--)
- x[--cnt[y[i].x]] = y[i];
- }
- void build() {
- for (int i = ; i < n; i++)
- rk[i] = str[i];
- for (int k = ; k <= n; k <<= ) {
- for (int i = ; i + k < n; i++)
- T1[i] = Pair3(rk[i], rk[i + k], i);
- for (int i = n - k; i < n; i++)
- T1[i] = Pair3(rk[i], , i);
- radix_sort(T1, T2);
- int diff = ;
- rk[T1[].id] = ;
- for (int i = ; i < n; i++)
- rk[T1[i].id] = (T1[i].x == T1[i - ].x && T1[i].y == T1[i - ].y) ? (diff) : (++diff);
- if (diff == n)
- break;
- }
- for (int i = ; i < n; i++)
- sa[--rk[i]] = i;
- }
- void get_height() {
- for (int i = , j, k = ; i < n; i++, (k) ? (k--) : ()) {
- if (rk[i]) {
- j = sa[rk[i] - ];
- while (i + k < n && j + k < n && str[i + k] == str[j + k]) k++;
- hei[rk[i]] = k;
- }
- }
- }
- void init_st() {
- st.init(n, hei);
- }
- int lcp(int x1, int x2) {
- if (x1 == x2)
- return n - x1 + ;
- x1 = rk[x1], x2 = rk[x2];
- if (x1 > x2)
- swap(x1, x2);
- return st.query(x1 + , x2);
- }
- int compare(int l1, int r1, int l2, int r2) {
- int len_lcp = lcp(l1, l2);
- int len1 = r1 - l1 + , len2= r2 - l2 + ;
- if (len_lcp >= len1 && len_lcp >= len2)
- return ;
- if (len_lcp < len1 && len_lcp < len2)
- return (str[l1 + len_lcp] < str[l2 + len_lcp]) ? (-) : ();
- return (len_lcp >= len1) ? (-) : ();
- }
- int query(int u, int v) { // u, v -> sa
- if (u == v)
- return n - sa[u];
- return st.query(u + , v);
- }
- const int& operator [] (int p) {
- return sa[p];
- }
- const int& operator () (int p) {
- return hei[p];
- }
- } SuffixArray;
- typedef class IndexedTree {
- public:
- int s;
- int *a;
- IndexedTree() { }
- IndexedTree(int n) : s(n) {
- a = new int[(s + )];
- pfill(a + , a + n + , );
- }
- ~IndexedTree() {
- delete[] a;
- }
- void add(int idx, int val) {
- for ( ; idx <= s; idx += (idx & (-idx)))
- a[idx] += val;
- }
- int query(int idx) {
- int rt = ;
- for ( ; idx; idx -= (idx & (-idx)))
- rt += a[idx];
- return rt;
- }
- int query(int l, int r) {
- return query(r) - query(l - );
- }
- } IndexedTree;
- typedef class Graph {
- protected:
- int dfs_clock;
- public:
- vector<int>* g;
- int *fa;
- int *in, *out;
- int *sz, *zson;
- int *dep, *top;
- Graph() { }
- Graph(vector<int>* g, int n) : dfs_clock(), g(g) {
- fa = new int[(n + )];
- in = new int[(n + )];
- out = new int[(n + )];
- sz = new int[(n + )];
- zson = new int[(n + )];
- dep = new int[(n + )];
- top = new int[(n + )];
- dfs1(, );
- dfs2(, true);
- }
- ~Graph() {
- #define rem(__) delete[] __;
- rem(fa) rem(in) rem(out) rem(sz) rem(zson) rem(dep) rem(top)
- }
- void dfs1(int p, int fa) {
- dep[p] = ((fa) ? (dep[fa] + ) : ());
- in[p] = ++dfs_clock;
- this->fa[p] = fa;
- sz[p] = ;
- int mx = -, id = -, e;
- for (unsigned i = ; i < g[p].size(); i++) {
- e = g[p][i];
- dfs1(e, p);
- sz[p] += sz[e];
- if (sz[e] > mx)
- mx = sz[e], id = e;
- }
- out[p] = dfs_clock;
- zson[p] = id;
- }
- void dfs2(int p, boolean ontop) {
- top[p] = ((ontop) ? (p) : (top[fa[p]]));
- if (~zson[p])
- dfs2(zson[p], false);
- for (int i = , e; i < (signed) g[p].size(); i++) {
- e = g[p][i];
- if (e == zson[p])
- continue;
- dfs2(e, true);
- }
- }
- int lca(int u, int v) {
- while (top[u] ^ top[v]) {
- if (dep[top[u]] < dep[top[v]])
- swap(u, v);
- u = fa[top[u]];
- }
- return (dep[u] < dep[v]) ? (u) : (v);
- }
- } Graph;
- #define pii pair<int, int>
- int n, L, K;
- int id[N];
- char str[N];
- SuffixArray sa;
- int endp[N >> ];
- char _str[N >> ];
- vector<int> endpos[N >> ];
- inline void init() {
- L = ;
- scanf("%d%d", &n, &K);
- for (int i = ; i <= n; i++) {
- scanf("%s", _str);
- if (i > ) {
- id[L] = -;
- str[L] = '#'; //"!@#$%^&*()-+"[i % 11];
- L += ;
- }
- for (char* p = _str; *p; p++) {
- id[L] = i;
- str[L] = *p;
- L++;
- }
- endp[i] = L;
- }
- sa.set(L, str);
- sa.build();
- sa.get_height();
- sa.init_st();
- }
- int cnt_node;
- vector<int> g[N << ];
- int d[N << ];
- int build_suffix_tree(int l, int r) {
- int curid = ++cnt_node;
- d[curid] = sa.query(l, r);
- if (l == r) {
- int p = sa[l];
- if (id[p] > )
- endpos[id[p]].push_back(curid);
- return curid;
- }
- for (int p = l, j, L, R, mid; p <= r; p = j + ) {
- L = p, R = r;
- char x = str[sa[p] + d[curid]];
- while (L <= R) {
- mid = (L + R) >> ;
- if (str[sa[mid] + d[curid]] == x)
- L = mid + ;
- else
- R = mid - ;
- }
- j = L - ;
- L = build_suffix_tree(p, j);
- g[curid].push_back(L);
- }
- return curid;
- }
- int res[N << ];
- void dfs(int p, Graph& G, IndexedTree& it) {
- res[p] = (it.query(G.in[p], G.out[p]) >= K) ? (d[p]) : (res[G.fa[p]]);
- for (int i = ; i < (signed) g[p].size(); i++) {
- dfs(g[p][i], G, it);
- }
- }
- inline void solve() {
- while (cnt_node)
- g[cnt_node--].clear();
- build_suffix_tree(, L - );
- IndexedTree it (cnt_node);
- Graph graph (g, cnt_node);
- for (int i = ; i <= n; i++) {
- it.add(graph.in[endpos[i][]], );
- for (int j = ; j < (signed) endpos[i].size(); j++) {
- it.add(graph.in[endpos[i][j]], );
- int g = graph.lca(endpos[i][j], endpos[i][j - ]);
- it.add(graph.in[g], -);
- }
- }
- dfs(, graph, it);
- for (int i = , p, l; i <= n; i++) {
- long long ans = ;
- for (int j = ; j < (signed) endpos[i].size(); j++) {
- p = endpos[i][j], l = d[p];
- ans += min(endp[i] - (L - l), res[p]);
- }
- printf("%lld ", ans);
- }
- }
- int main() {
- init();
- solve();
- return ;
- }
bzoj 3473 字符串 - 后缀数组 - 树状数组的更多相关文章
- AcWing:246. 区间最大公约数(线段树 + 增量数组(树状数组) + 差分序列)
给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一: 1.“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d. 2.“Q l r”,表示询问 A[l],A[l ...
- BZOJ 2754 SCOI 2012 喵星球上的点名 后缀数组 树状数组
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2068 Solved: 907[Submit][St ...
- BZOJ 2780 Sevenk Love Oimaster (后缀自动机+树状数组+dfs序+离线)
题目大意: 给你$n$个大串和$m$个询问,每次给出一个字符串$s$询问在多少个大串中出现过 好神的一道题 对$n$个大串建出广义$SAM$,建出$parent$树 把字符串$s$放到$SAM$里跑, ...
- BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树
[题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...
- [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】
题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...
- BZOJ 2743: [HEOI2012]采花 [树状数组 | 主席树]
题意: 查询区间中出现次数$>2$的颜色个数 一眼主席树,区间中$l \le last[i] \le r$的个数减去$l \le last[last[i]] \le r$的个数,搞两颗主席树来做 ...
- BZOJ.4826.[AHOI/HNOI2017]影魔(树状数组/莫队 单调栈)
BZOJ LOJ 洛谷 之前看\(mjt\)用莫队写了,以为是一种正解,码了3h结果在LOJ T了没A= = 心态爆炸(upd:发现是用C++11(NOI)交的,用C++11交就快一倍了...) 深刻 ...
- bzoj 3262 陌上花开 - CDQ分治 - 树状数组
Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...
- bzoj 2527 Meteors - 整体二分 - 树状数组
Description Byteotian Interstellar Union (BIU) has recently discovered a new planet in a nearby gala ...
- BZOJ 1396:识别子串 SA+树状数组+单调队列
1396: 识别子串 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 381 Solved: 243[Submit][Status][Discuss] ...
随机推荐
- [daily]gtk程序不跟随系统的dark主题
问题描述: 我的系统主题是dark的.在使用mysql-workbench是,里边的一些线条就跟随了系统文字的主要使用了灰白色. 这样在白色画布里就看不见这些线条了. 方法: 设置mysql-work ...
- MongoDB - Indexes
#explain command pp db[:zips].find(:state => 'MD').explain #List all indexes: db[:zips].indexes.e ...
- 洛谷P4640 王之财宝 [BJWC2008] 数论
正解:容斥+Lucas+组合数学 解题报告: 传送门! 和上一篇题解的题差不多,,,双倍经验趴大概算 还是说下还是有点儿区别的来着$QwQ$ 两个小差别分别港下$QwQ$ 首先有$m-n$件是无穷个的 ...
- C++ opencv调用resize修改插值方式遇到的坑
opencv提供的热死则函数原型如下:void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0 ...
- turtlebot3 ubuntu mate 实现vnc连接
tuutlebot3 ubuntu mate 实现vnc连接 摘要: 在turtlebot3 安装的nbuntu mate系统实验过. 实现内容 x11vnc 安装 x11vnc自动启动 vnc分辩率 ...
- 学号20175313 《实现Linux下cp XXX1 XXX2的功能(二)》第九周
目录 MyCP2 一.题目要求 二.题目理解 三.需求分析 四.设计思路 五.伪代码分析 六.代码链接 七.代码实现过程中遇到的问题 八.运行结果截图 九.心得体会 十.参考资料 MyCP2 一.题目 ...
- jenkins 判断某个job是否正在构建
其实很简单,访问jenkins job的xml api或者 json api,里面有两个key叫"lastBuild"和"lastCompletedBuild" ...
- Scala集合Map
在scala中Map分为可变长(mutable)和不可变长(immutable) /** * 不可变长map 长度一旦初始化,就不能在进行更改 */ // 通过箭头的方式创建map val map = ...
- Oracle 10053
[10053]alter session set events '10053 trace name context forever,level 1'; <Run your SQL here;&g ...
- Cocos Creator 动态设置Canvas的宽度与高度,更改适配
let c = this.node.getComponent(cc.Canvas);c.fitHeight = true;c.fitWidth = false; let h = 960 * cc.wi ...