转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:给出一棵树,1为根,边为字母,问从某个结点,向下走m步,路径形成一个字符串,要求字典序最大。
http://acm.hdu.edu.cn/showproblem.php?pid=4601
做法:直接做根本没法。。。每个结点孩子结点边上的字母可能相等。直接贪心都没法。m也很大。
我们如果知道从根到每个结点路径形成的字符串,
那么固定u,m,查询的话,终点必定是在同一层,depth[u] + m。从根到这个结点的字符串长度是一样的,而且必定存在LCP >= depth[u]。所以我们可以直接比较从根到终点的路径的字符串,而且对于每次查询,终点是在同一层。
我们就可以萌生离线做法,对于终点在同一层的查询一并处理。
那么我们需要求出根到每个结点的字典序排名,以及HASH值。
然后对于这样树型转线性的应该 不陌生,利用DFS的时间戳。
然后 对于每一层,可以用RMQ或者线段树查询最值。注意最值是字典序,不要用HASH值的大小。
接下来的问题是怎么得到字典序,原因在于原来的树每个结点的孩子中有相同的字母,那么我们就重构Trie。
大概就可以解决了:
step 1:构造Trie,避免边上字母一样的情况,作一些合并,原来的结点映射到Trie上的结点。
step 2:遍历Trie,给原来的结点标上rank值。
step 3:遍历原来的树,得到时间戳。
step 4:将查询分类之后,处理每一层,将同一层的值放到RMQ或者线段树中。
step 5:每个查询,二分得到对应区间,区间查询。
注意 :数据中有m = 0 的情况,坑啊。。。。。。。。。。。。。。。输出0
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson step << 1 #define rson step << 1 | 1 #pragma comment(linker,"/STACK:100000000,100000000") using namespace std; typedef long long LL; const int N = 200005; const LL MOD = 1000000007LL; const LL HASH = 26LL; struct Edge { int v , next , ch ; }e[N << 1]; struct Trie { Trie *next[26]; vector <int> v; void init () { v.clear(); memset (next , 0 , sizeof(next)); } }s[N]; struct Question { int u , d , id; void input (int _i) { scanf ("%d %d" , &u , &d); id = _i; } }question[N]; struct Seg_tree { int left , right; int maxrank; LL hash; }L[N << 2]; vector<Question>askondep[N]; int n , start[N] , tot , idx; LL hash[N] , fac[N] = {1}; int ans[N]; void _add (int u , int v , int c) { e[tot].v = v; e[tot].ch = c; e[tot].next = start[u]; start[u] = tot ++; } void add (int u , int v , int c) { _add (u , v , c); _add (v , u , c); } Trie *NewNode () { Trie *t = &s[idx ++]; t->init(); return t; } void bulidtrie (Trie *p , int u , int pre , LL h) { p -> v.push_back (u); hash[u] = h; for (int i = start[u] ; i != -1 ; i = e[i].next) { int v = e[i].v , ch = e[i].ch; if (v == pre) continue; if (p -> next[ch] == NULL) p -> next[ch] = NewNode (); bulidtrie (p -> next[ch] , v , u , (h * HASH + ch) % MOD); } } int nowrank , rank[N]; void getrank (Trie *p ) { for (int i = 0 ; i < p -> v.size() ; i ++) { rank[p -> v[i]] = nowrank; } for (int i = 0 ; i < 26 ; i ++) { if (p -> next[i] != NULL) { nowrank ++; getrank (p -> next[i]); } } } vector<int> ondepth[N]; int depth[N] , id[N] , left_id[N] , right_id[N] , id_cnt , maxdep , mapping[N]; void caldepth (int u , int pre , int dep) { depth[u] = dep; id[u] = ++id_cnt; mapping[id_cnt] = u; left_id[u] = id_cnt + 1; ondepth[dep].push_back (id_cnt); maxdep = max (maxdep , dep); for (int i = start[u] ; i != -1 ; i = e[i].next) { int v = e[i].v; if (v == pre) continue; caldepth (v , u , dep + 1); } right_id[u] = id_cnt; } void push_up (int step) { if (L[lson].maxrank > L[rson].maxrank) { L[step].maxrank = L[lson].maxrank; L[step].hash = L[lson].hash; } else { L[step].maxrank = L[rson].maxrank; L[step].hash = L[rson].hash; } } void bulid (int step , int l , int r , int d) { L[step].left = l; L[step].right = r; if (l == r) { L[step].maxrank = rank[mapping[ondepth[d][l]]]; L[step].hash = hash[mapping[ondepth[d][l]]]; return ; } int m = (l + r) >> 1; bulid (lson , l , m , d); bulid (rson , m + 1 , r , d); push_up (step); } pair<int , LL> query (int step , int l , int r) { if (l < L[step].left || r > L[step].right || l > r) return make_pair(-1 , -1); if (L[step].left == l && L[step].right == r) { return make_pair (L[step].maxrank , L[step].hash); } int m = (L[step].left + L[step].right) >> 1; if (r <= m) return query (lson , l , r); else if (l > m) return query (rson , l , r); else { pair<int , int> u = query (lson , l , m); pair<int , int> v = query (rson , m + 1 , r); if (u.first > v.first) return u; return v; } } int main () { #ifndef ONLINE_JUDGE freopen ("input.txt" , "r" , stdin); freopen ("output.txt" , "w" , stdout); #endif for (int i = 1 ; i < N ; i ++) fac[i] = (fac[i - 1] * 26LL) % MOD; int t , out = 0; scanf ("%d" , &t); while (t --) { tot = 0;idx = 0; memset (start , -1 , sizeof(start)); scanf ("%d" , &n); for (int i = 1 ; i < n ; i ++) { int u , v ; char str[5]; scanf ("%d %d %s" , &u , &v , str); add (u , v , str[0] - 'a'); } Trie *root = NewNode (); bulidtrie (root , 1 , -1 , 0LL); nowrank = 0; getrank (root); id_cnt = 0;maxdep = 1; caldepth (1 , -1 , 1); int q; scanf ("%d" , &q); for (int i = 0 ; i < q ; i ++) { question[i].input(i); if (question[i].d == 0) ans[i] = 0; else if (depth[question[i].u] + question[i].d <= maxdep) askondep[depth[question[i].u] + question[i].d].push_back (question[i]); else ans[i] = -1; } for (int dep = 1 ; dep <= maxdep ; dep ++) { if (askondep[dep].size () == 0) continue; int m = ondepth[dep].size() - 1; bulid (1 , 0 , m , dep); for (int i = 0 ; i < askondep[dep].size() ; i ++) { int u = askondep[dep][i].u , d = askondep[dep][i].d , id = askondep[dep][i].id; int l = left_id[u] , r = right_id[u]; l = lower_bound (ondepth[dep].begin () , ondepth[dep].end () , l) - ondepth[dep].begin (); r = upper_bound (ondepth[dep].begin () , ondepth[dep].end () , r) - ondepth[dep].begin () - 1; pair<int , LL> ret = query (1 , l , r); if (ret.second == -1) ans[id] = -1; else ans[id] = ((ret.second - (LL)hash[u] * fac[d]) % MOD + MOD) % MOD; } } for (int i = 0 ; i < q ; i ++) { if (ans[i] == -1) puts ("IMPOSSIBLE"); else printf("%d\n" , ans[i]); } for (int i = 1 ; i <= maxdep ; i ++) { ondepth[i].clear(); askondep[i].clear(); } } return 0; }