广搜确定各点深度, 并以此沿广搜顺序将点加入数组 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
*/