关闭

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

标签: ACM熟练剖分ac自动机
310人阅读 评论(0) 收藏 举报
分类:

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;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:126631次
    • 积分:3404
    • 等级:
    • 排名:第10163名
    • 原创:223篇
    • 转载:13篇
    • 译文:0篇
    • 评论:5条
    最新评论