BZOJ 2780 SPOJ 8093 Sevenk Love Oimaster 后缀自动机+fenwick

来源:互联网 发布:沙克也干了知乎 编辑:程序博客网 时间:2024/04/29 11:11

题目大意:给出一些字符串,给出一些询问,每次问当前串在源串中的几个中出现过。


思路:将所有源串建立广义后缀自动机。每次新的一个串的时候,把last清成root,往里面加的时候,如果last指针往下走的时候已经有节点了,就需要拓展一个新的节点出来,否则就不满足广义后缀自动机的性质。此外,每一个节点代表的不一定是一个串,可能代表的是多个串的子串,所以要在每个点后面挂链,来表示这个节点是属于哪几个串中的子串。后面的事情就比较简单了,把后缀树建立出来,弄出DFS序,离线处所有询问,变成在一段序列中出现过多少不同的数字,弄一个树状数组维护一下。

其实和喵星球上的点名是差不多的,但是那个题我用的后缀数组暴力的,这个题会T。

还有这个题坑爹的卡内存啊,字符集太大,直接建立肯定mle,用map的话就不能用指针,我这还是第一次用数组写啊。。DT死了。。。


CODE:

//#define _CRT_SECURE_NO_DEPRECATE#include <map>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 200010using namespace std;struct Graph{int head[MAX],total;int next[MAX],aim[MAX];void Add(int x,int y) {next[++total] = head[x];aim[total] = y;head[x] = total;}}G,repre;struct Ask{pair<int,int> interval;int id;Ask(pair<int,int> _,int __):interval(_),id(__) {}Ask() {}bool operator <(const Ask &a)const {return interval.second < a.interval.second;}}ask[MAX];int len[MAX],father[MAX];map<int,int> tranc[MAX];int cnt,root,last;inline int NewNode(int _){len[++cnt] = _;return cnt;}void Initialize(){root = last = NewNode(0);}inline void Add(int c,int i){int p = tranc[last][c];if(p) {if(len[p] == len[last] + 1)last = p;else {int rep = NewNode(len[last] + 1);father[rep] = father[p];father[p] = rep;tranc[rep] = tranc[p];for(int temp = last; temp && tranc[temp][c] == p; temp = father[temp])tranc[temp][c] = rep;last = rep;}}else {int np = NewNode(len[last] + 1);for(p = last; p && !tranc[p][c]; p = father[p])tranc[p][c] = np;if(!p)father[np] = root;else {int q = tranc[p][c];if(len[q] == len[p] + 1)father[np] = q;else {int nq = NewNode(len[p] + 1);father[nq] = father[q];father[q] = father[np] = nq;tranc[nq] = tranc[q];for(; p && tranc[p][c] == q; p = father[p])tranc[p][c] = nq;}}last = np;}repre.Add(last,i);}pair<int,int> subtree[MAX];int seq[MAX],_clock;void DFS(int x){seq[++_clock] = x;subtree[x].first = _clock;for(int i = G.head[x]; i; i = G.next[i])DFS(G.aim[i]);subtree[x].second = _clock;}char s[MAX << 1];inline pair<int,int> Find(){int now = root,length = strlen(s);for(int i = 0; i < length; ++i) {if(!tranc[now][s[i]])return make_pair(-1,-1);now = tranc[now][s[i]];}return subtree[now];}int fenwick[MAX];inline void Fix(int x,int c){for(; x <= cnt; x += x&-x)fenwick[x] += c;}inline int GetSum(int x){int re = 0;for(; x; x -= x&-x)re += fenwick[x];return re;}int strings,asks;int last_add[MAX],ans[MAX];int main(){Initialize();scanf("%d%d",&strings,&asks);for(int i = 1; i <= strings; ++i) {scanf("%s",s);int length = strlen(s);last = root;for(int j = 0; j < length; ++j)Add(s[j],i);}for(int i = 1; i <= cnt; ++i)if(father[i])G.Add(father[i],i);DFS(1);for(int i = 1; i <= asks; ++i) {scanf("%s",s);ask[i] = Ask(Find(),i);}sort(ask + 1,ask + asks + 1);int now = 1;while(ask[now].interval.first == -1 && now <= asks)++now;for(int i = 1; i <= cnt; ++i) {for(int j = repre.head[seq[i]]; j; j = repre.next[j]) {int col = repre.aim[j];Fix(i,1);if(last_add[col])Fix(last_add[col],-1);last_add[col] = i;}for(; ask[now].interval.second == i; ++now)ans[ask[now].id] = GetSum(ask[now].interval.second) - GetSum(ask[now].interval.first - 1);}for(int i = 1; i <= asks; ++i)printf("%d\n",ans[i]);return 0;}


2 0