題目描述數據結構
輸入測試
輸出加密
樣例輸入spa
1
5 8
1 3 3 2 2
1 1 3 3
1 0
0 0
3 0
1 3
2 1
2 0
6 2
4 1blog
樣例輸出string
1
2
3
1
1
2
1
1it
題解io
樹鏈的並+STL-set+DFS序+可持久化線段樹ast
若是沒有深度限制,那麼對於一種顏色,子樹內包含該顏色的節點爲:全部該顏色節點到根節點路徑覆蓋的全部節點,即樹鏈的並。class
所以對於每一種顏色求樹鏈的並,支持鏈加操做;查詢單個點的時候就是查詢單點值。樹上差分後轉變爲單點加、子樹求和,使用DFS序轉化爲區間問題後使用數據結構維護。
那麼有深度限制呢?咱們按照深度維護可持久化線段樹,第 $i$ 個版本咱們只考慮深度小於等於 $i$ 的節點的影響。此時須要使用STL-set維護每一個顏色的樹鏈的並。
查詢時直接查詢depth[x]+d版本對應的可持久化線段樹中,x節點子樹內的權值和便可。
時間複雜度 $O(n\log n)$ 。
#include <set> #include <cstdio> #include <cstring> #include <algorithm> #define N 100010 using namespace std; set<int> s[N]; set<int>::iterator it; int c[N] , head[N] , to[N] , next[N] , cnt , fa[N][20] , deep[N] , log[N] , pos[N] , ref[N] , last[N] , tp; int id[N] , sum[N << 6] , ls[N << 6] , rs[N << 6] , root[N] , tc; inline void add(int x , int y) { to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt; } void dfs(int x) { int i; pos[x] = ++tp , ref[tp] = x; for(i = 1 ; (1 << i) <= deep[x] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1]; for(i = head[x] ; i ; i = next[i]) fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]); last[x] = tp; } inline int lca(int x , int y) { int i; if(deep[x] < deep[y]) swap(x , y); for(i = log[deep[x] - deep[y]] ; ~i ; i -- ) if(deep[x] - deep[y] >= (1 << i)) x = fa[x][i]; if(x == y) return x; for(i = log[deep[x]] ; ~i ; i -- ) if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i]) x = fa[x][i] , y = fa[y][i]; return fa[x][0]; } bool cmp(int a , int b) { return deep[a] < deep[b]; } void update(int p , int a , int l , int r , int x , int &y) { y = ++tc , sum[y] = sum[x] + a; if(l == r) return; int mid = (l + r) >> 1; if(p <= mid) rs[y] = rs[x] , update(p , a , l , mid , ls[x] , ls[y]); else ls[y] = ls[x] , update(p , a , mid + 1 , r , rs[x] , rs[y]); } int query(int b , int e , int l , int r , int x) { if(b <= l && r <= e) return sum[x]; int mid = (l + r) >> 1 , ans = 0; if(b <= mid) ans += query(b , e , l , mid , ls[x]); if(e > mid) ans += query(b , e , mid + 1 , r , rs[x]); return ans; } int main() { int T; scanf("%d" , &T); while(T -- ) { cnt = tp = tc = 0; int n , m , i , p = 1 , x , y , lastans = 0; scanf("%d%d" , &n , &m); for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &c[i]) , s[i].clear() , id[i] = i , head[i] = 0; for(i = 2 ; i <= n ; i ++ ) scanf("%d" , &x) , add(x , i) , log[i] = log[i >> 1] + 1; dfs(1) , sort(id + 1 , id + n + 1 , cmp); for(root[0] = i = 0 ; i < n ; i ++ ) { if(i) root[i] = root[i - 1]; while(p <= n && deep[id[p]] <= i) { x = y = 0; it = s[c[id[p]]].lower_bound(pos[id[p]]); if(it != s[c[id[p]]].end()) y = ref[*it]; if(it != s[c[id[p]]].begin()) x = ref[*--it]; update(pos[id[p]] , 1 , 1 , n , root[i] , root[i]); if(x) update(pos[lca(x , id[p])] , -1 , 1 , n , root[i] , root[i]); if(y) update(pos[lca(y , id[p])] , -1 , 1 , n , root[i] , root[i]); if(x && y) update(pos[lca(x , y)] , 1 , 1 , n , root[i] , root[i]); s[c[id[p]]].insert(pos[id[p]]) , p ++ ; } } while(m -- ) { scanf("%d%d" , &x , &y) , x ^= lastans , y = min(deep[x] + (y ^ lastans) , n - 1); printf("%d\n" , lastans = query(pos[x] , last[x] , 1 , n , root[y])); } } return 0; }