hdu 5566 Clarke and room(ac自动机+树链剖分)

原创 2015年11月17日 16:22:38

Clarke and room

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 11    Accepted Submission(s): 3


Problem Description
Clarke is a patient with multiple personality disorder. One day, Clarke split into n guys, the ith Clarke named namei
They live in n rooms connected by n1 roads. There is only one path between any two rooms. Now, their landlord is to check the name with a long list. The landlord will check m times, at ith time, he wants to know the maximum length of the names which appear on the list si on the path between xi and yirooms(including xi and yi).
 

Input
The first line contains an integer T(1T10), the number of test cases. 
For each test case: 
The first line contains an integer n(1n100000)
Then n lines follow, the ith line contains a string namei
Then n1 lines follow, the ith line contains an integer fi+1(1fi+1i), denoting there is an edge between i+1 and fi+1
Then m lines follow, the ith line contains two integers xi,yi(1xi,yin) and a string si
Every string is composed by lower letter. 
1|namei|,|si|,ni=1|namei|,mi=1|si|100000
 

Output
For each test case, print m lines with the answers.
 

Sample Input
1 4 a ab abc d 1 2 1 3 1 1 abc 1 1 d 1 3 abc
 

Sample Output
1 0 3 Hint: Ask 1: $a$ appears in $abc$, so the answer is $1$. Ask 2: There is no one appears in $d$, so the answer is $0$. Ask 3: $a$, $ab$ and $abc$ appear in $abc$, so the answer is $3$.

题意:给一棵n个点的树,每个节点有一个串,然后有m个查询x y s,查询点x走到点y路径上(包含x,y)的串是s的子串的最长的长度是多少

题解:这题我用的是离线的方法,首先熟练剖分作查询,然后标记好线段树的每个点被哪些查询访问,最后单独对每个存在查询的线段树结点建立一棵自动机,把这个线段树结点包含的区间的串全部插入自动机,然后对逐一对访问过这个区间的串作一次查询更新对应查询。复杂度是(name + s)* logn * logn级别的

    代码如下,函数名字已经很清楚说明了函数功能


#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <queue>

using namespace std;

const int N = 26;
const int maxn = 100008;

int n, p[maxn], fp[maxn]; 

inline void mymax(int &x, int y){
	if(y > x) x = y;
}

struct tire{
	int nxt[N + 2], fail, is, len;
	void init(){
		memset(nxt, 0, sizeof(nxt));
		fail = is = len = 0;
	}
};

struct act{
	tire t[maxn];
	int root = 0, all;

	void init(){
		t[all = 0].init();
	}
	void insert(string s){
		int now = 0;

		for(int i = 0; i < (int)s.length(); i++){
			int cc = s[i] - 'a';
			if(!t[now].nxt[cc]){
				t[now].nxt[cc] = ++all;
				t[all].init();
			}
			now = t[now].nxt[cc];
		}
		t[now].is = 1;
		t[now].len = s.length();
	}
	void build(){
		int now = 0;
		queue<int> q;

		for(int i = 0; i < N; i++){
			if(!t[now].nxt[i]) continue;
			else{
				t[t[now].nxt[i]].fail = 0;
				q.push(t[now].nxt[i]);
			}
		}
		while(!q.empty()){
			now = q.front();
			q.pop();
			for(int i = 0; i < N; i++){
				if(!t[now].nxt[i]){
					t[now].nxt[i] = t[t[now].fail].nxt[i];
				}
				else{
					t[t[now].nxt[i]].fail = t[t[now].fail].nxt[i];
					mymax(t[t[now].nxt[i]].len, t[t[t[now].nxt[i]].fail].len);
					q.push(t[now].nxt[i]);
				}
			}
		}
	}
	int run(string s){
		int res = 0, now = 0;

		for(int i = 0; i < (int)s.length(); i++){
			int cc = s[i] - 'a';
			now = t[now].nxt[cc];
			mymax(res, t[now].len);
		}

		return res;
	}
}ac;

string s[maxn], ans[maxn];
int res[maxn];

struct segtree{
	vector<int> v[maxn << 2];

	void init(int pos, int l, int r){
		v[pos].clear();
		if(l == r) return ;
		int mid = (l + r) >> 1;
		init(pos << 1, l, mid);
		init(pos << 1 | 1, mid + 1, r);
	}
	void query(int pos, int l, int r, int tl, int tr, int vv){
		if(tl <= l && r <= tr){
			v[pos].push_back(vv);
			return ;
		}
		int mid = (l + r) >> 1;
		if(tr <= mid){
			query(pos << 1, l, mid, tl, tr, vv);
		}
		else if(tl > mid){
			query(pos << 1 | 1, mid + 1, r, tl, tr, vv);
		}
		else{
			query(pos << 1, l, mid, tl, mid, vv);
			query(pos << 1 | 1, mid + 1, r, mid + 1, tr, vv);
		}
	}
	void getans(int pos, int l, int r){
		if(v[pos].size()){
			//printf("pos  %d   %d   %d\n", pos, l, r);
			ac.init();
			for(int i = l; i <= r; i++){
				ac.insert(s[fp[i]]);
			}
			ac.build();
			for(int i = 0; i < (int)v[pos].size(); i++){
				mymax(res[v[pos][i]], ac.run(ans[v[pos][i]]));
			}
		}
		if(l == r) return ;
		int mid = (l + r) >> 1;
		getans(pos << 1, l, mid);
		getans(pos << 1 | 1, mid + 1, r);
	}
}st;

struct edge{
	int to, nxt;
};

struct slpf{
	edge e[maxn << 2];
	int head[maxn], top[maxn], fa[maxn];
	int deep[maxn], num[maxn];
	int son[maxn], tot, pos, root;

	void init(){
		tot = 0;
		memset(head, -1, sizeof(head));
		pos = 1;
		memset(son, -1, sizeof(son));
	}
	void addedge(int u, int v){
		e[tot].to = v;
		e[tot].nxt = head[u];
		head[u] = tot++;
	}
	void dfs1(int u, int pre, int d){
		deep[u] = d;
		fa[u] = pre;
		num[u] = 1;
		for(int i = head[u]; i != -1; i = e[i].nxt){
			int v = e[i].to;
			if(v != pre){
				dfs1(v, u, d + 1);
				num[u] += num[v];
				if(son[u] == -1 || num[v] > num[son[u]])
					son[u] = v;
			}
		}
	}
	void getpos(int u, int sp){
		top[u] = sp;
		p[u] = pos++;
		fp[p[u]] = u;
		if(son[u] == -1) return ;
		getpos(son[u], sp);
		for(int i = head[u]; i != -1; i = e[i].nxt){
			int v = e[i].to;
			if(v != son[u] && v != fa[u])
				getpos(v, v);
		}
	}
	void build(){
		dfs1(1, 0, 0);
		getpos(1, 1);
	}
	void query(int u, int v, int vv){
		int f1 = top[u], f2 = top[v];

		while(f1 != f2){
			if(deep[f1] < deep[f2]){
				swap(f1, f2);
				swap(u, v);
			}
			st.query(1, 1, n, p[f1], p[u], vv);
			//printf("query   %d   %d\n", p[f1], p[u]);
			u = fa[f1];
			f1 = top[u];
		}
		if(deep[u] > deep[v]) swap(u, v);
		st.query(1, 1, n, p[u], p[v], vv);
	}
}spt;

int main(){
	int _, x, y, m;

	//freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(0);
	cin >> _;
	while(_--){
		cin >> n;
		st.init(1, 1, n);
		spt.init();
		for(int i = 1; i <= n; i++){
			cin >> s[i];
		}
		for(int i = 1; i < n; i++){
			cin >> x;
			spt.addedge(i + 1, x);
			spt.addedge(x, i + 1);
		}
		spt.build();
		cin >> m;
		for(int i = 1; i <= m; i++){
			cin >> x >> y >> ans[i];
			spt.query(x, y, i);
		}
		memset(res, 0, sizeof(res));
		st.getans(1, 1, n);
		for(int i = 1; i <= m; i++){
			cout << res[i] << endl;
		}
	}

	return 0;
}


【HDU】5566 Clarke and room【树链剖分+AC自动机】

题目链接:Clarke and room#include using namespace std ;typedef long long LL ;#define ls ( o
  • u013368721
  • u013368721
  • 2016年11月01日 11:09
  • 495

hdu 5566 Clarke and room ac自动机+树链剖分+主席树

#include #include #include #include #include #include using namespace std; #define N 100020 #...
  • u013654696
  • u013654696
  • 2016年01月20日 21:02
  • 347

HDU 3695 AC自动机 裸题

题意: T个测试数据 n个模版 母串   问: 模版,在母串或翻转母串中出现的个数 注意模版会重复( 一样的单词可能重复出现 )     #include #include #include u...
  • qq574857122
  • qq574857122
  • 2013年10月06日 22:57
  • 2002

HDU 4787 GRE Words Revenge(在线AC自动机)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4787题意:Coach Pang学习英语单词,总共有n个操作,2种操作。每行读入一个字符串。 如果字符串...
  • u014357885
  • u014357885
  • 2015年09月10日 21:54
  • 812

HDU 2296 Ring(AC自动机+DP)

HDU 2296 Ring(AC自动机+DP) http://acm.hdu.edu.cn/showproblem.php?pid=2296 题意:给你M个单词构成一个词典,每个单词有一个权值(单词出...
  • u013480600
  • u013480600
  • 2014年04月13日 12:23
  • 1168

hdu2296 Ring (AC自动机+dp)

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission...
  • Kirito_Acmer
  • Kirito_Acmer
  • 2016年02月11日 16:57
  • 416

HDU 6086 AC自动机+状压dp

题意:题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6086 给出m个单词,要构造出长度为2*L的包含这全部m个单词的字符串,并且保证这个字符串非对称...
  • Bahuia
  • Bahuia
  • 2017年08月13日 19:48
  • 478

hdu5384(AC自动机+纪录重复单词出现的次数)

题意: 给出n篇文章,m个单词,输出每篇文章中单词出现的次数,其中单词会重复。 思路: AC自动机模板题,添加一个单词的结尾标记记录即可。这里我们用了kuangbin的模板。 ...
  • ms961516792
  • ms961516792
  • 2015年08月13日 16:29
  • 483

HDU 5069 Harry And Biological Teacher AC自动机 + 线段树优化 (BestCoder Round 14 D)

题目大意: 就是对于给出的n个字符串(n 大致思路: 首先这个题可以用AC自动机或者后缀自动机来做, 我使用的是AC自动机, 将输入的所有串建立一个AC自动机, 对于每一个串A的后缀和...
  • u013738743
  • u013738743
  • 2015年05月28日 15:44
  • 770

AC自动机模板(数组+指针)hdu2222

Online Judge Online Exercise Online Teaching Online Contests Exercise Author F.A.Q Hand In...
  • u010660276
  • u010660276
  • 2014年08月20日 17:01
  • 531
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hdu 5566 Clarke and room(ac自动机+树链剖分)
举报原因:
原因补充:

(最多只允许输入30个字)