參考博文:http://blog.csdn.net/qwe2434127/article/details/49819975
http://blog.csdn.net/qq_24489717/article/details/50569644
dfs序比較重要的性質:一棵子樹的所有節點在dfs序里是連續一段,主要就是利用這個性質來解題.
作為預處理,首先將將樹的所有節點按深度保存起來,每個深度的所有節點用一個線性結構保存,每個深度的節點相對順序要和前序遍歷一致。
然后從樹的根節點進行dfs,對於每個節點記錄兩個信息,一個是dfs進入該節點的時間戳in[id],另一個是dfs離開該節點的時間戳out[id]。
最后對於每次查詢,求節點v在深度h的所有子節點,只需將深度為h並且dfs進入時間戳在in[v]和out[v]之間的所有節點都求出來即可,由於對於 每個深度的所有節點,相對順序和前序遍歷的順序以致,那么他們的dfs進入時間戳也是遞增的,於是可以通過二分搜索求解。
Poj 3321:
題型一:對某個點X權值加上一個數W,查詢某個子樹X里所有點權值和。
解:列出dfs序,實現修改一個數,查詢一段序列的和,顯然這個序列可以用樹狀數組維護。
#include <iostream> #include <stdio.h> #include <math.h> #include <string.h> using namespace std; typedef long long LL; const int N = 500005; struct Edge{ int v,next; }edge[N]; int head[N],tot,c[N]; int in[N],out[N]; bool have[N]; int cnt; void init(){ tot = 0; cnt = 0; memset(head,-1,sizeof(head)); memset(c,0,sizeof(c)); } void addEdge(int u,int v,int &k){ edge[k].v = v,edge[k].next = head[u],head[u] = k++; } void dfs(int u){ in[u] = ++cnt; for(int k=head[u];k!=-1;k=edge[k].next){ dfs(edge[k].v); } out[u] = cnt; } int lowbit(int x){ return x&(-x); } int getsum(int id){ int sum = 0; for(int i=id;i>=1;i-=lowbit(i)){ sum+=c[i]; } return sum; } void update(int id,int x){ for(int i=id;i<=cnt;i+=lowbit(i)){ c[i]+=x; } } int main() { int n,m; while(scanf("%d",&n)!=EOF){ init(); for(int i=0;i<n-1;i++){ int u,v; scanf("%d%d",&u,&v); addEdge(u,v,tot); } dfs(1); /*for(int i=1;i<=n;i++){ printf("%d %d\n",in[i],out[i]); }*/ for(int i=1;i<=n;i++){ have[i] = 1; update(in[i],1); } int q; scanf("%d",&q); while(q--){ char s[5]; int x; scanf("%s%d",s,&x); if(s[0]=='Q'){ printf("%d\n",getsum(out[x])-getsum(in[x]-1)); }else{ if(have[x]) update(in[x],-1); else update(in[x],1); have[x] = !have[x]; } } } return 0; }
hdu 3886 :
統計某一個結點下面比編號比其小的結點數目.
#pragma comment(linker,"/STACK:1024000000,1024000000") #include <iostream> #include <stdio.h> #include <math.h> #include <string.h> using namespace std; typedef long long LL; const int N = 500005; struct Edge{ int v,next; }edge[N]; int head[N],tot,c[N]; int in[N],out[N]; bool have[N]; int cnt; void init(){ tot = 0; cnt = 0; memset(head,-1,sizeof(head)); memset(c,0,sizeof(c)); } void addEdge(int u,int v,int &k){ edge[k].v = v,edge[k].next = head[u],head[u] = k++; } void dfs(int u,int fa){ in[u] = ++cnt; for(int k=head[u];k!=-1;k=edge[k].next){ if(edge[k].v == fa) continue; dfs(edge[k].v,u); } out[u] = cnt; } int lowbit(int x){ return x&(-x); } int getsum(int id){ int sum = 0; for(int i=id;i>=1;i-=lowbit(i)){ sum+=c[i]; } return sum; } void update(int id,int x){ for(int i=id;i<=cnt;i+=lowbit(i)){ c[i]+=x; } } int main() { int n,q; while(scanf("%d%d",&n,&q)!=EOF,n+q){ init(); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); addEdge(u,v,tot); addEdge(v,u,tot); } dfs(q,-1); bool flag = true; for(int i=1;i<=n;i++){ if(!flag) printf(" "); printf("%d",getsum(out[i])-getsum(in[i]-1)); flag = false; update(in[i],1); } printf("\n"); } return 0; }
hdu 5692:利用DFS序將樹形結構轉換成為線段樹.便於維護和查找.
http://www.cnblogs.com/liyinggang/p/5925196.html
hdu 5468:DFS序+容斥原理 ,求解每個結點下面與其互質的結點的個數。
http://www.cnblogs.com/liyinggang/p/5926105.html
bzoj 2819:DFS序+博弈+樹狀數組+lca,維護樹上的一條路上的異或值.
http://www.cnblogs.com/liyinggang/p/5927232.html
update中...