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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DFS序

發布時間:2024/4/15 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DFS序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

DFS序

總結:

1、樹轉化為線性:將樹通過dfs轉化為線性結構,這就是dfs序,和樹鏈剖分有點相似

2、普通樹轉化為線段樹:記錄每個節點構成的樹(子樹)的起點和終點,起點是自己,這樣每個點就構成了一個區間,然后對區間的操作就和線段樹和樹狀數組一樣了。

3、DFS序主要用來做子樹的更新,因為DFS序中子樹都是連續的。時間復雜度看樹的儲存結構,O(1)。

4、樹的儲存可以用圖來存儲,圖的數組模擬鄰接矩陣:小兵應該先武裝好自己,然后再加入隊伍,隊長負責周轉(管最前面一個)。

?

?

詳解:

給定一棵n個節點的樹,m次查詢,每次查詢需要求出某個節點深度為h的所有子節點。

?

對于這個問題如果試圖去對每個節點保存所有深度的子節點,在數據大的時候內存會吃不消;或者每次查詢的時候去遍歷一遍,當數據大的時候,時間效率會非常低。

?

此時如果使用dfs序維護樹結構就可以輕松地解決這個問題。

?

作為預處理,首先將將樹的所有節點按深度保存起來,每個深度的所有節點用一個線性結構保存,每個深度的節點相對順序要和前序遍歷一致。

?

然后從樹的根節點進行dfs,對于每個節點記錄兩個信息,一個是dfs進入該節點的時間戳in[id],另一個是dfs離開該節點的時間戳out[id]。

?

最后對于每次查詢,求節點v在深度h的所有子節點,只需將深度為h并且dfs進入時間戳在in[v]和out[v]之間的所有節點都求出來即可,由于對于每個深度的所有節點,相對順序和前序遍歷的順序以致,那么他們的dfs進入時間戳也是遞增的,于是可以通過二分搜索求解。

?

分析

Step 1:

如下圖,可以看到,由于普通的樹并不具有區間的性質,所以在考慮使用線段樹作為解題思路時,需要對給給定的數據進行轉化,首先對這棵樹進行一次dfs遍歷,記錄dfs序下每個點訪問起始時間與結束時間,記錄起始時間是前序遍歷,結束時間是后序遍歷,同時對這課樹進行重標號。

?

Step 2:

???????? 如下圖,DFS之后,那么樹的每個節點就具有了區間的性質。



?

???????? 那么此時,每個節點對應了一個區間,而且可以看到,每個節點對應的區間正好“管轄”了它子樹所有節點的區間,那么對點或子樹的操作就轉化為了對區間的操作。

【PS: 如果對樹的遍歷看不懂的話,不妨待會對照代碼一步一步調試,或者在紙上模擬過程~】

Step 3:

???????? 這個時候,每次對節點進行更新或者查詢,就是線段樹和樹狀數組最基本的實現了…

?

樹是一種非線性結構,一般而言,我們總是想辦法將其轉化為線性結構,將樹上操作包括子樹操作、路徑操作等轉化為數組上的區間操作,從而在一個較為理想的復雜度內加以解決。將樹“拍平”的方法有很多,例如歐拉序、HLD等。實際上歐拉序也是在DFS過程中得到的。不過通常而言,我們所說的DFS序是指:每個節點進出棧的時間序列

?
考慮上圖中樹的DFS序,應為?

其中,每個節點均會出現2次,第一次是進入DFS的時刻,第二次是離開DFS的時刻。分別稱之為InOut。在區間操作中,如果某個節點出現了2次,則該節點將被“抵消”。所以通常會將Out時刻對應的點設置為負數。

樹的DFS序列有幾個有用的性質:

  • 任意子樹是連續的。例如子樹BEFK,在序列中對應BEEFKKFB;子樹CGHI,在序列中對應連續區間CGGHHIIC。
  • 任意點對(a,b)之間的路徑,可分為2種情況,首先令lcaa、b的最近公共祖先:?
  • lcaa、b之一,則a、b之間的In時刻的區間或者Out時刻區間就是其路徑。例如AK之間的路徑就對應區間ABEEFK,或者KFBCGGHHIICA。
  • lca另有其人,則a、b之間的路徑為In[a]、Out[b]之間的區間或者In[b]、Out[a]之間的區間。另外,還需額外加上lca!!!考慮EK路徑,對應為EFK再加上B??紤]EH之間的路徑,對應為EFKKFBCGGH再加上A。
  • 利用這些性質,可以利用DFS序列完成子樹操作和路徑操作,同時也有可能將莫隊算法應用到樹上從而得到樹上莫隊。

    ?

    ?

    代碼:

    dfs序是處理樹上問題很重要的一個武器,主要能夠解決對于一個點,它的子樹上的一些信息的維護。?
    就比如那天百度之星round1A的1003題,就是dfs序+線段樹維護每個點到0點的距離,然后對于每個點的更新,只需要更新它和它的子樹上的點到0點的距離,查詢的話就是它的子樹上的最大值即可?
    我的dfs序開的空間就是n,因為只在入的地方時間戳++,出來的地方時間戳不變,線段樹的每個節點應該是時間戳

    1 void dfs(int u,int fa){ 2 p1[u]=++ti; 3 dfsnum[ti]=u; 4 for(int i=head[u];i!=-1;i=edge[i].next){ 5 int v=edge[i].v; 6 if(v==fa) continue; 7 dfs(v,u); 8 } 9 p2[u]=ti;//時間戳不變,空間為O(n) 10 }

    ?

    例題:

    BZOJ4034需要在樹上完成3類操作,單點更新,子樹更新,以及根到指定節點的路徑查詢。利用性質1以及性質2.1即可完成,連LCA都無需求出。對整個DFS序列使用線段樹進行維護,注意到整個序列實際上有正有負,因此額外用一個域來表示正數的個數。

    4034: [HAOI2015]樹上操作

    Time Limit:?10 Sec??Memory Limit:?256 MB
    Submit:?6323??Solved:?2094
    [Submit][Status][Discuss]

    Description

    有一棵點數為 N 的樹,以點 1 為根,且樹點有邊權。然后有 M 個 操作,分為三種: 操作 1 :把某個節點 x 的點權增加 a 。 操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。 操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。

    Input

    第一行包含兩個整數 N, M 。表示點數和操作數。接下來一行 N 個整數,表示樹中節點的初始權值。接下來 N-1? 行每行三個正整數 fr, to , 表示該樹中存在一條邊 (fr, to) 。再接下來 M 行,每行分別表示一次操作。其中 第一個數表示該操作的種類( 1-3 ) ,之后接這個操作的參數( x 或者 x a ) 。

    Output

    對于每個詢問操作,輸出該詢問的答案。答案之間用換行隔開。

    Sample Input

    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3

    Sample Output

    6
    9
    13

    HINT

    ?

    ?對于 100% 的數據, N,M<=100000 ,且所有輸入數據的絕對值都不會超過 10^6 。

    ?

    Source

    鳴謝bhiaibogf提供

    1 #include <cstdio> 2 #include <climits> 3 #include <algorithm> 4 #include <iostream> 5 using namespace std; 6 7 int const SIZE = 100100; 8 typedef long long weight_t; 9 10 struct edge_t{// 11 int to; 12 int next; 13 }Edge[SIZE<<1];//雙向的 所以*2 14 int Vertex[SIZE]; 15 int ECnt; 16 weight_t W[SIZE]; 17 18 //數組模擬鄰接矩陣:頂點記錄的是下一個點,頂點負責轉運 19 inline void mkEdge(int a,int b){//造a-b這條邊 20 //先把節點的信息補充好,再建立聯系 21 //先武裝好自己,然后再圖報效 22 //每個隊的長官記錄每個隊節點的分配信息 23 Edge[ECnt].to = b; 24 Edge[ECnt].next = Vertex[a]; 25 Vertex[a] = ECnt++; 26 27 Edge[ECnt].to = a; 28 Edge[ECnt].next = Vertex[b]; 29 Vertex[b] = ECnt++; 30 } 31 32 int InIdx[SIZE],OutIdx[SIZE]; 33 int InOut[SIZE<<1]; 34 int NewIdx[SIZE<<1]; 35 int NCnt; 36 37 void dfs(int node,int parent){ 38 NewIdx[NCnt] = node; 39 InOut[NCnt] = 1; 40 InIdx[node] = NCnt++; 41 for(int next=Vertex[node];next;next=Edge[next].next){ 42 int son = Edge[next].to; 43 if ( son != parent ) dfs(son,node); 44 } 45 NewIdx[NCnt] = node; 46 InOut[NCnt] = -1; 47 OutIdx[node] = NCnt++; 48 } 49 50 int N; 51 weight_t StSum[SIZE<<3]; 52 weight_t Lazy[SIZE<<3]; 53 int Flag[SIZE<<3];//The count of the positive number in the range 54 55 inline int lson(int x){return x<<1;} 56 inline int rson(int x){return lson(x)|1;} 57 58 inline void _pushUp(int t){ 59 StSum[t] = StSum[lson(t)] + StSum[rson(t)]; 60 Flag[t] = Flag[lson(t)] + Flag[rson(t)]; 61 } 62 63 inline void _pushDown(int t){ 64 if ( 0LL == Lazy[t] ) return; 65 66 weight_t& x = Lazy[t]; 67 68 int son = lson(t); 69 StSum[son] += Flag[son] * x; 70 Lazy[son] += x; 71 72 son = rson(t); 73 StSum[son] += Flag[son] * x; 74 Lazy[son] += x; 75 76 x = 0LL; 77 } 78 79 void build(int t,int s,int e){ 80 Lazy[t] = 0LL; 81 if ( s == e ){ 82 StSum[t] = InOut[s] * W[NewIdx[s]]; 83 Flag[t] = InOut[s]; 84 return; 85 } 86 87 int m = ( s + e ) >> 1; 88 build(lson(t),s,m); 89 build(rson(t),m+1,e); 90 _pushUp(t); 91 } 92 93 void modify(int t,int s,int e,int a,int b,weight_t delta){ 94 if ( a <= s && e <= b ){ 95 StSum[t] += Flag[t] * delta; 96 Lazy[t] += delta; 97 return; 98 } 99 100 _pushDown(t); 101 int m = ( s + e ) >> 1; 102 if ( a <= m ) modify(lson(t),s,m,a,b,delta); 103 if ( m < b ) modify(rson(t),m+1,e,a,b,delta); 104 _pushUp(t); 105 } 106 107 weight_t query(int t,int s,int e,int a,int b){ 108 if ( a <= s && e <= b ){ 109 return StSum[t]; 110 } 111 112 _pushDown(t); 113 114 weight_t ret = 0LL; 115 int m = ( s + e ) >> 1; 116 if ( a <= m ) ret += query(lson(t),s,m,a,b); 117 if ( m < b ) ret += query(rson(t),m+1,e,a,b); 118 return ret; 119 } 120 121 inline weight_t query(int x){ 122 return query(1,1,N<<1,1,InIdx[x]); 123 } 124 125 inline void modify(int x,weight_t delta){ 126 modify(1,1,N<<1,InIdx[x],InIdx[x],delta); 127 modify(1,1,N<<1,OutIdx[x],OutIdx[x],delta); 128 } 129 130 inline void modifySubtree(int x,weight_t delta){ 131 modify(1,1,N<<1,InIdx[x],OutIdx[x],delta); 132 } 133 134 //這里樹的儲存方式用的是圖里面的數組仿鄰接矩陣 135 inline void initTree(int n){ 136 ECnt = NCnt = 1; 137 //vertex是頂點,這就是存儲邊的方式 138 fill(Vertex,Vertex+n+1,0); 139 } 140 141 int M; 142 bool read(){ 143 if ( EOF == scanf("%d%d",&N,&M) ) return false; 144 145 initTree(N); 146 for(int i=1;i<=N;++i)scanf("%lld",W+i);//讀權值 147 148 int a,b; 149 for(int i=1;i<N;++i){ 150 scanf("%d%d",&a,&b);//讀每一條邊 151 mkEdge(a,b);//造邊 152 } 153 cout<<"Edge[i].to"<<" "<<"Edge[i].next"<<endl; 154 for(int i=0;i<=20;i++){ 155 cout<<Edge[i].to<<" "<<Edge[i].next<<endl; 156 } 157 dfs(1,0); 158 build(1,1,N<<1); 159 return true; 160 } 161 162 void proc(){ 163 int cmd,x; 164 weight_t a; 165 while(M--){ 166 scanf("%d%d",&cmd,&x); 167 switch(cmd){ 168 case 1:scanf("%lld",&a);modify(x,a);break; 169 case 2:scanf("%lld",&a);modifySubtree(x,a);break; 170 case 3:printf("%lld\n",query(x));break; 171 } 172 } 173 } 174 int main(){ 175 freopen("in.txt","r",stdin); 176 while( read() ) proc(); 177 return 0; 178 }

    ?

    ?

    HDU 3887?
    題目傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=3887?
    問你對于每個節點,它的子樹上標號比它小的點有多少個?
    子樹的問題,dfs序可以很輕松的解決,因為點在它的子樹上,所以在線段樹中,必定在它的兩個時間戳的區間之間,所以我們只需要從小到大考慮,它的區間里有多少個點已經放了,然后再把它放進去。很容易的解決了?
    代碼:

    1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <string> 7 #include <vector> 8 #include <cstdio> 9 #include <cctype> 10 #include <cstring> 11 #include <sstream> 12 #include <cstdlib> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker, "/STACK:102400000,102400000") 16 17 using namespace std; 18 #define MAX 500005 19 #define MAXN 6005 20 #define maxnode 15 21 #define sigma_size 30 22 #define lson l,m,rt<<1 23 #define rson m+1,r,rt<<1|1 24 #define lrt rt<<1 25 #define rrt rt<<1|1 26 #define middle int m=(r+l)>>1 27 #define LL long long 28 #define ull unsigned long long 29 #define mem(x,v) memset(x,v,sizeof(x)) 30 #define lowbit(x) (x&-x) 31 #define pii pair<int,int> 32 #define bits(a) __builtin_popcount(a) 33 #define mk make_pair 34 #define limit 10000 35 36 //const int prime = 999983; 37 const int INF = 0x3f3f3f3f; 38 const LL INFF = 0x3f3f; 39 const double pi = acos(-1.0); 40 //const double inf = 1e18; 41 const double eps = 1e-8; 42 const LL mod = 1e9+7; 43 const ull mx = 133333331; 44 45 /*****************************************************/ 46 inline void RI(int &x) { 47 char c; 48 while((c=getchar())<'0' || c>'9'); 49 x=c-'0'; 50 while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; 51 } 52 /*****************************************************/ 53 54 struct Edge{ 55 int v,next; 56 }edge[MAX*2]; 57 int head[MAX]; 58 int tot; 59 int p1[MAX]; 60 int p2[MAX]; 61 int ti; 62 int sum[MAX<<2]; 63 64 void init(){ 65 mem(head,-1); 66 tot=0;ti=0; 67 } 68 69 void add_edge(int a,int b){ 70 edge[tot]=(Edge){b,head[a]}; 71 head[a]=tot++; 72 } 73 74 void dfs(int u,int fa){ 75 p1[u]=++ti; 76 for(int i=head[u];i!=-1;i=edge[i].next){ 77 int v=edge[i].v; 78 if(v==fa) continue; 79 dfs(v,u); 80 } 81 p2[u]=ti; 82 } 83 84 void build(int l,int r,int rt){ 85 sum[rt]=0; 86 if(l==r) return; 87 middle; 88 build(lson); 89 build(rson); 90 } 91 92 void pushup(int rt){ 93 sum[rt]=sum[lrt]+sum[rrt]; 94 } 95 96 void update(int l,int r,int rt,int pos,int d){ 97 if(l==r){ 98 sum[rt]+=d; 99 return; 100 } 101 middle; 102 if(pos<=m) update(lson,pos,d); 103 else update(rson,pos,d); 104 pushup(rt); 105 } 106 107 int query(int l,int r,int rt,int L,int R){ 108 if(L<=l&&r<=R) return sum[rt]; 109 middle; 110 int ret=0; 111 if(L<=m) ret+=query(lson,L,R); 112 if(R>m) ret+=query(rson,L,R); 113 return ret; 114 } 115 116 int main(){ 117 int n,p; 118 while(cin>>n>>p&&n){ 119 init(); 120 for(int i=1;i<n;i++){ 121 int a,b; 122 scanf("%d%d",&a,&b); 123 add_edge(a,b); 124 add_edge(b,a); 125 } 126 dfs(p,-1); 127 build(1,n,1); 128 for(int i=1;i<=n;i++){ 129 printf("%d",query(1,n,1,p1[i],p2[i])); 130 if(i==n) printf("\n"); 131 else printf(" "); 132 update(1,n,1,p1[i],1); 133 } 134 } 135 return 0; 136 }

    ?

    poj 3321?
    題目傳送門:http://poj.org/problem?id=3321?
    這題是一開始告訴你樹上每個節點都有1個蘋果,然后你對一個節點操作,如果有蘋果,就拿走,沒蘋果,就放上,然后詢問你以x為根的子樹上有多少個蘋果。?
    dfs序水題,代碼:

    1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <string> 7 #include <vector> 8 #include <cstdio> 9 #include <cctype> 10 #include <cstring> 11 #include <sstream> 12 #include <cstdlib> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker, "/STACK:102400000,102400000") 16 17 using namespace std; 18 #define MAX 500005 19 #define MAXN 6005 20 #define maxnode 15 21 #define sigma_size 30 22 #define lson l,m,rt<<1 23 #define rson m+1,r,rt<<1|1 24 #define lrt rt<<1 25 #define rrt rt<<1|1 26 #define middle int m=(r+l)>>1 27 #define LL long long 28 #define ull unsigned long long 29 #define mem(x,v) memset(x,v,sizeof(x)) 30 #define lowbit(x) (x&-x) 31 #define pii pair<int,int> 32 #define bits(a) __builtin_popcount(a) 33 #define mk make_pair 34 #define limit 10000 35 36 //const int prime = 999983; 37 const int INF = 0x3f3f3f3f; 38 const LL INFF = 0x3f3f; 39 const double pi = acos(-1.0); 40 //const double inf = 1e18; 41 const double eps = 1e-8; 42 const LL mod = 1e9+7; 43 const ull mx = 133333331; 44 45 /*****************************************************/ 46 inline void RI(int &x) { 47 char c; 48 while((c=getchar())<'0' || c>'9'); 49 x=c-'0'; 50 while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; 51 } 52 /*****************************************************/ 53 54 struct Edge{ 55 int v,next; 56 }edge[MAX*2]; 57 int head[MAX]; 58 int tot; 59 int p1[MAX]; 60 int p2[MAX]; 61 int ti; 62 int sum[MAX<<2]; 63 64 void init(){ 65 mem(head,-1); 66 tot=0;ti=0; 67 } 68 69 void add_edge(int a,int b){ 70 edge[tot]=(Edge){b,head[a]}; 71 head[a]=tot++; 72 } 73 74 void dfs(int u,int fa){ 75 p1[u]=++ti; 76 for(int i=head[u];i!=-1;i=edge[i].next){ 77 int v=edge[i].v; 78 if(v==fa) continue; 79 dfs(v,u); 80 } 81 p2[u]=ti; 82 } 83 84 void pushup(int rt){ 85 sum[rt]=sum[lrt]+sum[rrt]; 86 } 87 88 void build(int l,int r,int rt){ 89 if(l==r){ 90 sum[rt]=1; 91 return; 92 } 93 middle; 94 build(lson); 95 build(rson); 96 pushup(rt); 97 } 98 99 void update(int l,int r,int rt,int pos){ 100 if(l==r){ 101 sum[rt]=sum[rt]^1; 102 return; 103 } 104 middle; 105 if(pos<=m) update(lson,pos); 106 else update(rson,pos); 107 pushup(rt); 108 } 109 110 int query(int l,int r,int rt,int L,int R){ 111 if(L<=l&&r<=R) return sum[rt]; 112 middle; 113 int ret=0; 114 if(L<=m) ret+=query(lson,L,R); 115 if(R>m) ret+=query(rson,L,R); 116 return ret; 117 } 118 119 int main(){ 120 int n; 121 cin>>n; 122 init(); 123 for(int i=1;i<n;i++){ 124 int a,b; 125 scanf("%d%d",&a,&b); 126 add_edge(a,b); 127 add_edge(b,a); 128 } 129 dfs(1,-1); 130 build(1,n,1); 131 int m; 132 scanf("%d",&m); 133 while(m--){ 134 char op; 135 int a; 136 getchar(); 137 scanf("%c%d",&op,&a); 138 if(op=='Q') printf("%d\n",query(1,n,1,p1[a],p2[a])); 139 else update(1,n,1,p1[a]); 140 } 141 return 0; 142 }

    ?

    ?

    CodeForces 620E?
    題目傳送門:http://codeforces.com/problemset/problem/620/E?
    給你一棵樹,每個節點都有顏色,然后問你子樹上有多少種不同的顏色?
    考慮到顏色一共只有60種,所以可以直接二進制記錄,每個節點記錄這個節點的顏色,然后區間直接左右子樹或起來,然后對x為根的子樹都變成c顏色,區間賦值,需要pushdown,pushup。?
    有個坑點就是需要記錄每個時間戳是哪個點,然后在build線段樹的時候,sum[rt]=c[dfsnum[l]],這個坑點我錯了好久,因為線段樹的節點的下標應該是時間戳。GG,仍需努力?
    代碼:

    1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <string> 7 #include <vector> 8 #include <cstdio> 9 #include <cctype> 10 #include <cstring> 11 #include <sstream> 12 #include <cstdlib> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker, "/STACK:102400000,102400000") 16 17 using namespace std; 18 #define MAX 400005 19 #define MAXN 6005 20 #define maxnode 15 21 #define sigma_size 30 22 #define lson l,m,rt<<1 23 #define rson m+1,r,rt<<1|1 24 #define lrt rt<<1 25 #define rrt rt<<1|1 26 #define middle int m=(r+l)>>1 27 #define LL long long 28 #define ull unsigned long long 29 #define mem(x,v) memset(x,v,sizeof(x)) 30 #define lowbit(x) (x&-x) 31 #define pii pair<int,int> 32 #define bits(a) __builtin_popcount(a) 33 #define mk make_pair 34 #define limit 10000 35 36 //const int prime = 999983; 37 const int INF = 0x3f3f3f3f; 38 const LL INFF = 0x3f3f; 39 const double pi = acos(-1.0); 40 //const double inf = 1e18; 41 const double eps = 1e-8; 42 const LL mod = 1e9+7; 43 const ull mx = 133333331; 44 45 /*****************************************************/ 46 inline void RI(int &x) { 47 char c; 48 while((c=getchar())<'0' || c>'9'); 49 x=c-'0'; 50 while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; 51 } 52 /*****************************************************/ 53 54 struct Edge{ 55 int v,next; 56 }edge[MAX*2]; 57 int head[MAX]; 58 int tot; 59 int c[MAX]; 60 int p1[MAX]; 61 int p2[MAX]; 62 int ti; 63 int dfsnum[MAX]; 64 LL sum[MAX<<2]; 65 int col[MAX<<2]; 66 void init(){ 67 mem(head,-1); 68 tot=0;ti=0; 69 } 70 71 void add_edge(int a,int b){ 72 edge[tot]=(Edge){b,head[a]}; 73 head[a]=tot++; 74 } 75 76 void dfs(int u,int fa){ 77 p1[u]=++ti; 78 dfsnum[ti]=u; 79 for(int i=head[u];i!=-1;i=edge[i].next){ 80 int v=edge[i].v; 81 if(v==fa) continue; 82 dfs(v,u); 83 } 84 p2[u]=ti; 85 } 86 87 void pushup(int rt){ 88 sum[rt]=sum[lrt]|sum[rrt]; 89 } 90 91 void pushdown(int rt){ 92 if(col[rt]){ 93 col[lrt]=col[rrt]=col[rt]; 94 sum[lrt]=sum[rrt]=(1LL<<col[rt]); 95 col[rt]=0; 96 } 97 } 98 void build(int l,int r,int rt){ 99 col[rt]=0; 100 if(l==r){ 101 sum[rt]=(1LL<<c[dfsnum[l]]); 102 return; 103 } 104 middle; 105 build(lson); 106 build(rson); 107 pushup(rt); 108 } 109 110 void update(int l,int r,int rt,int L,int R,int d){ 111 if(L<=l&&r<=R){ 112 sum[rt]=(1LL<<d); 113 col[rt]=d; 114 return; 115 } 116 middle; 117 pushdown(rt); 118 if(L<=m) update(lson,L,R,d); 119 if(R>m) update(rson,L,R,d); 120 pushup(rt); 121 } 122 123 LL query(int l,int r,int rt,int L,int R){ 124 if(L<=l&&r<=R) return sum[rt]; 125 middle; 126 LL ret=0; 127 pushdown(rt); 128 if(L<=m) ret|=query(lson,L,R); 129 if(R>m) ret|=query(rson,L,R); 130 return ret; 131 } 132 133 int main(){ 134 //freopen("in.txt","r",stdin); 135 int n,m; 136 while(cin>>n>>m){ 137 init(); 138 for(int i=1;i<=n;i++) scanf("%d",&c[i]); 139 for(int i=1;i<n;i++){ 140 int a,b; 141 scanf("%d%d",&a,&b); 142 add_edge(a,b); 143 add_edge(b,a); 144 } 145 dfs(1,-1); 146 build(1,n,1); 147 //cout<<query(1,n,1,p1[6],p2[6]); 148 while(m--){ 149 int op,a; 150 scanf("%d%d",&op,&a); 151 if(op==1){ 152 int cc; 153 scanf("%d",&cc); 154 update(1,n,1,p1[a],p2[a],cc); 155 } 156 else { 157 LL k=query(1,n,1,p1[a],p2[a]); 158 //cout<<k<<" "; 159 int num=0; 160 while(k){ 161 int tmp=k%2; 162 k/=2; 163 num+=tmp; 164 //if(tmp) cout<<tmp<<" "; 165 } 166 printf("%d\n",num); 167 } 168 } 169 } 170 return 0; 171 }

    ?

    轉載于:https://www.cnblogs.com/Renyi-Fan/p/8244003.html

    總結

    以上是生活随笔為你收集整理的DFS序的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。