日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BZOj #4771. 七彩树(主席树+dfn序+lca)

發(fā)布時間:2023/12/3 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOj #4771. 七彩树(主席树+dfn序+lca) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

BZOj #4771. 七彩樹

  • description
  • solution
  • code

description

給定一棵n個點的有根樹,編號依次為1到n,其中1號點是根節(jié)點。每個節(jié)點都被染上了某一種顏色,其中第i個節(jié)點的顏色為c[i]。如果c[i]=c[j],那么我們認為點i和點j擁有相同的顏色。定義depth[i]為i節(jié)點與根節(jié)點的距離,為了方便起見,你可以認為樹上相鄰的兩個點之間的距離為1。站在這棵色彩斑斕的樹前面,你將面臨m個問題。

每個問題包含兩個整數(shù)x和d,表示詢問x子樹里且depth不超過depth[x]+d的所有點中出現(xiàn)了多少種本質(zhì)不同的顏色。請寫一個程序,快速回答這些詢問。

Input

第一行包含一個正整數(shù)T(1<=T<=500),表示測試數(shù)據(jù)的組數(shù)。

每組數(shù)據(jù)中,第一行包含兩個正整數(shù)n(1<=n<=100000)和m(1<=m<=100000),表示節(jié)點數(shù)和詢問數(shù)。

第二行包含n個正整數(shù),其中第i個數(shù)為c[i](1<=c[i]<=n)c[i](1<=c[i]<=n)c[i](1<=c[i]<=n),分別表示每個節(jié)點的顏色。

第三行包含n-1個正整數(shù),其中第i個數(shù)為f[i+1](1<=f[i]<i)f[i+1](1<=f[i]<i)f[i+1](1<=f[i]<i),表示節(jié)點i+1的父親節(jié)點的編號。

接下來m行,每行兩個整數(shù)x(1<=x<=n)和d(0<=d<n),依次表示每個詢問。

輸入數(shù)據(jù)經(jīng)過了加密,對于每個詢問,如果你讀入了x和d,那么真實的x和d分別是x xor last和d xor last,

其中l(wèi)ast表示這組數(shù)據(jù)中上一次詢問的答案,如果這是當(dāng)前數(shù)據(jù)的第一組詢問,那么last=0。

輸入數(shù)據(jù)保證n和m的總和不超過500000。

Output

對于每個詢問輸出一行一個整數(shù),即答案。

Sample Input

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 1

Sample Output

1 2 3 1 1 2 1 1

solution

詢問子樹內(nèi)的問題,通常都轉(zhuǎn)化成dfn序,然后就可以用線段樹維護,變成區(qū)間問題

詢問距離不超過depx+ddep_x+ddepx?+d,那就按深度排序后,建主席樹

則對于深度為iii的版本的線段樹只會存在深度≤i\le ii的點

線段樹上的點管轄的區(qū)間就是其子樹

其點存的值,就是管轄區(qū)間內(nèi)不同顏色的個數(shù)

最后只需要處理子樹內(nèi)多個點有同樣顏色的修改

具體而言,根據(jù)dfn序,對于新增點iii,在線段樹上對應(yīng)的點進行+1

找到與其顏色相同的dfn小于iii的最大dfn序?qū)?yīng)的點,記為iii的前驅(qū)

那么求出這兩個點的lca,從lca往上的點都含有這兩個點,但只需要算一個,所以在線段樹上lca對應(yīng)的葉子節(jié)點,進行-1

同理。找到與其顏色相同的dfn大于iii的最小dfn序?qū)?yīng)的點,記為iii的后繼

那么求出這兩個點的lca,從lca往上的點都含有這兩個點,但只需要算一個,所以在線段樹上lca對應(yīng)的葉子節(jié)點,進行-1

但是前驅(qū)和后繼的lca又多減了111,所以要對其進行+1操作

code

#include <set> #include <cstdio> #include <iostream> #include <algorithm> using namespace std; #define maxn 100005 set < int > s[maxn]; struct node { int id, dep; }t[maxn]; int T, n, m, cnt; int root[maxn], c[maxn], dep[maxn], dfn[maxn], St[maxn], Ed[maxn], mp[maxn], head[maxn], to[maxn], nxt[maxn]; int f[maxn][20];void dfs( int u ) {dep[u] = dep[f[u][0]] + 1;dfn[u] = St[u] = ++ cnt;mp[cnt] = u;for( int i = 1;i < 20;i ++ )f[u][i] = f[f[u][i - 1]][i - 1];for( int i = head[u];i;i = nxt[i] ) dfs( to[i] );Ed[u] = cnt; }struct Node { int lson, rson, sum; }tree[maxn * 50];void modify( int &now, int lst, int l, int r, int pos, int k ) {tree[now = ++ cnt] = tree[lst];tree[now].sum += k;if( l == r ) return;int mid = ( l + r ) >> 1;if( pos <= mid ) modify( tree[now].lson, tree[lst].lson, l, mid, pos, k );else modify( tree[now].rson, tree[lst].rson, mid + 1, r, pos, k ); }int query( int now, int l, int r, int L, int R ) {if( r < L or R < l ) return 0;if( L <= l and r <= R ) return tree[now].sum;int mid = ( l + r ) >> 1;return query( tree[now].lson, l, mid, L, R ) + query( tree[now].rson, mid + 1, r, L, R ); }int lca( int u, int v ) {if( dep[u] < dep[v] ) swap( u, v );for( int i = 19;~ i;i -- ) if( dep[f[u][i]] >= dep[v] ) u = f[u][i];if( u == v ) return u;for( int i = 19;~ i;i -- ) if( f[u][i] ^ f[v][i] ) u = f[u][i], v = f[v][i];return f[u][0]; }int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ ) head[i] = 0, s[i].clear();for( int i = 1;i <= n;i ++ ) scanf( "%d", &c[i] );cnt = 1;for( int i = 2;i <= n;i ++ ) {scanf( "%d", &f[i][0] );to[cnt] = i, nxt[cnt] = head[f[i][0]], head[f[i][0]] = cnt ++;}cnt = 0;dfs( 1 );for( int i = 1;i <= n;i ++ ) t[i].id = i, t[i].dep = dep[i];sort( t + 1, t + n + 1, []( node x, node y ) { return x.dep < y.dep; } );cnt = 0;for( int i = 1;i <= n;i ++ ) {root[t[i].dep] = root[t[i - 1].dep];int id = t[i].id, d = t[i].dep;modify( root[d], root[d], 1, n, dfn[id], 1 );auto it = s[c[id]].lower_bound( dfn[id] );int pre = -1, nxt = -1;if( it != s[c[id]].end() ) {nxt = *it;modify( root[d], root[d], 1, n, dfn[lca( id, mp[nxt] )], -1 );}if( it != s[c[id]].begin() ) {pre = * (-- it);modify( root[d], root[d], 1, n, dfn[lca( id, mp[pre] )], -1 );}if( ~ pre and ~ nxt )modify( root[d], root[d], 1, n, dfn[lca( mp[pre], mp[nxt] )], 1 );s[c[id]].insert( dfn[id] );}int last = 0, x, d;while( m -- ) {scanf( "%d %d", &x, &d );x ^= last, d ^= last;printf( "%d\n", last = query( root[dep[x] + d], 1, n, St[x], Ed[x] ) );}cnt = 0;}return 0; } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的BZOj #4771. 七彩树(主席树+dfn序+lca)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。