HDU 4601

3 篇文章 0 订阅

广搜确定各点深度, 并以此沿广搜顺序将点加入数组 Sequence,序列里的深度逐渐增加,先序遍历树并依次编号,确定每个点及其子树的的编号范围,在Sequence 中二分查找某一深度的点的左右边界(Sequence 中的点的编号在某一深度其实是逐渐增加的) RMQ 查询最值。至于字典序,则在 遍历树的时候模拟字典树插入,然后求出每个点实际字典序(从根节点到它本身所连成的这个字符串字典序)

#pragma comment(linker,"/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 110000;
const int mod = (int) (1e9 + 7);
int tp[maxn], Log[30];
struct Range_Query {
	PII r[19][maxn];
	int n, i, j, k;
	void make(int a[], int Seq[]) {
		for (i = 1; i <= n; ++i)
			r[0][i] = PII(a[i], Seq[i]);
		for (i = 0; i < 19; ++i) {
			k = Log[i];
			for (j = 1; j + k <= n; ++j) {
				r[i + 1][j] = max(r[i][j], r[i][j + k]);
			}
		}
	}
	PII query(int L, int R) {
		if (R == L)
			return r[0][L];
		k = tp[R - L];
		return max(r[k][L], r[k][R - Log[k]]);
	}
} RMQ;

//==========================================================
struct node {
	int v, next, ch;
	node(int v = 0, int next = -1, int ch = 0) :
			v(v), next(next), ch(ch) {
	}
} edge[maxn << 2];
int head[maxn], e;
LL Hash[maxn + 111], POW[maxn];
int Sequence[maxn], cnt;
int Ccnt;
int lhs[maxn], rhs[maxn];
int Left[maxn], Right[maxn];
int dis[maxn];
int order[maxn], N, M;
int val[maxn];
bool vis[maxn];
int arr[maxn];
int Depth[maxn];
void add_edge(int u, int v, int ch) {
	edge[e] = node(v, head[u], ch);
	head[u] = e++;
	edge[e] = node(u, head[v], ch);
	head[v] = e++;
}
void bfs() {
	static int q[maxn], front, rear;
	memset(vis, false, sizeof(vis));
	memset(Left, 0x7f, sizeof(Left));
	memset(Right, -1, sizeof(Right));
	front = rear = 0;
	q[rear++] = 1;
	int i, u, v;
	Sequence[++cnt] = 1;
	vis[1] = true;
	dis[1] = 0;
	while (front < rear) {
		u = q[front++];
		for (i = head[u]; ~i; i = edge[i].next) {
			v = edge[i].v;
			if (vis[v])
				continue;
			dis[v] = dis[u] + 1;

			q[rear++] = v;
			Sequence[++cnt] = v;
			Left[dis[v]] = min(Left[dis[v]], cnt);
			Right[dis[v]] = max(Right[dis[v]], cnt);
			vis[v] = true;
		}
	}
}
void find_index(int u, int dep, int &L, int &R) {
	int low = Left[dis[u] + dep], high = Right[dis[u] + dep];
	int l, r, m;
	l = low, r = high;
	while (l <= r) {
		m = (l + r) >> 1;
		if (val[m] >= lhs[u])
			L = m, r = m - 1;
		else
			l = m + 1;
	}
	l = low, r = high;
	while (l <= r) {
		m = (l + r) >> 1;
		if (val[m] <= rhs[u])
			R = m, l = m + 1;
		else
			r = m - 1;
	}

}
void dfs(int u, int pre = -1) {
	int i, v;
	order[u] = ++Ccnt;
	lhs[u] = Ccnt;
	LL h;
	Depth[u] = dis[u];
	h = Hash[u] * 26;
	if (h >= mod)
		h %= mod;
	for (i = head[u]; ~i; i = edge[i].next) {
		v = edge[i].v;
		if (v == pre)
			continue;
		Hash[v] = h + edge[i].ch;
		if (Hash[v] >= mod)
			Hash[v] %= mod;
		dfs(v, u);
		Depth[u] = max(Depth[u], Depth[v]);
	}
	rhs[u] = Ccnt;
}
//==========================================================
int Rank[maxn];
struct TrieTree {
	int rt, tot;
	int cnt;
	struct node {
		int next[26];
		int cnt;
		void init() {
			cnt = 0;
			memset(next, 0, sizeof(next));
		}
	} tb[maxn];
	void init() {
		rt = tot = cnt = 0;
		tb[rt].init();
	}
	void insert(char s[]) {
		int i, rt = 0, t;
		for (i = 0; s[i]; ++i) {
			t = s[i] - 'a';
			if (!tb[rt].next[t]) {
				tb[++tot].init();
				tb[rt].next[t] = tot;
			}
			rt = tb[rt].next[t];
		}
	}
	void dfs(int u, int rt, int ch, int pre = -1) {
		int i, v, t;
		//printf("u %d rt %d  tot %d %c\n", u, rt, tot, ch + 'a');
		for (i = head[u]; ~i; i = edge[i].next) {
			v = edge[i].v;
			if (v == pre)
				continue;
			t = edge[i].ch;
			if (!tb[rt].next[t]) {
				tb[++tot].init();
				tb[rt].next[t] = tot;
			}
			dfs(v, tb[rt].next[t], t, u);
		}
	}
	void CalRank(int rt, int pre = -1) {
		int i;
		//printf("rt %d\n", rt);

		tb[rt].cnt = cnt++;
		for (i = 0; i < 26; ++i) {
			if (tb[rt].next[i])
				CalRank(tb[rt].next[i], rt);
		}
	}
	void go(int u, int rt, int pre = -1) {
		int i, v, t;
		Rank[u] = tb[rt].cnt;
		for (i = head[u]; ~i; i = edge[i].next) {
			v = edge[i].v;
			if (v == pre)
				continue;
			t = edge[i].ch;
			go(v, tb[rt].next[t], u);
		}
	}
} Trie;
//==========================================================
void debug(int u, int pre = -1) {
	int i, v;
	printf("u %d Rank %d\n", u, Rank[u]);
	for (i = head[u]; ~i; i = edge[i].next) {
		v = edge[i].v;
		if (v == pre)
			continue;
		debug(v, u);
	}
}
//=========================
int main() {
	int i, j, u, v, dep;
	char s[14];
	POW[0] = 1;
	for (i = 1; i <= maxn; ++i) {
		POW[i] = POW[i - 1] * 26;
		if (POW[i] >= mod)
			POW[i] %= mod;
	}
	Log[0] = 1;
	for (i = 1; i < 20; ++i)
		Log[i] = Log[i - 1] << 1;
	tp[1] = 0;
	i = 0;
	for (j = 2; j < maxn; ++j) {
		if (Log[i + 1] < j)
			tp[j] = ++i;
		else
			tp[j] = i;
		//printf("%d %d\n",j,tp[j]);
	}
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &N);
		Ccnt = e = cnt = 0;
		memset(head, -1, sizeof(head));
		for (i = 1; i < N; ++i) {
			scanf("%d%d%s", &u, &v, s);
			add_edge(u, v, s[0] - 'a');
		}
		Trie.init();
		Trie.dfs(1, 0, 0);
		Trie.CalRank(0);
		Trie.go(1, 0);
		bfs();
		dfs(1, 0);
		
		
		for (i = 1; i <= cnt; ++i)
			val[i] = order[Sequence[i]];
		
		for (i = 1; i <= cnt; ++i) {
			arr[i] = Rank[Sequence[i]];
		}
		
		int L, R;
		
		RMQ.n = cnt;
		RMQ.make(arr, Sequence);
		

		int delta;
		scanf("%d", &M);
		PII tmp;
		LL ans;
		while (M--) {
			scanf("%d%d", &u, &dep);
			
			if (dis[u] + dep > Depth[u]) {
				puts("IMPOSSIBLE");
			} else {
				find_index(u, dep, L, R);
				tmp = RMQ.query(L, R + 1);
				v = tmp.second;
				delta = dis[v] - dis[u];
				ans = Hash[v] - Hash[u] * POW[delta];
				ans = (ans % mod + mod) % mod;

				printf("%I64d\n", ans);
			}
		}
	}
	return 0;
}
/*
 10
 1 2 a
 1 3 b
 2 4 c
 2 5 b
 2 6 c
 5 10 v
 6 7 z
 3 9 y
 3 8 x
 4
 1 3
 2 2
 9 1
 1 2

 20
 1 2 a
 1 3 b
 2 4 c
 2 5 b
 2 6 c

 5 10 v
 6 7 z
 3 9 y
 3 8 x
 3 17 h

 11 15 t
 7 15 a
 10 16 z
 16 18 z
 18 19 z

 18 20 y
 7 12 x
 8 14 a
 8 13 y
 5
 1 6
 2 3
 3 2
 2 4
 7 2

 */


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值