dfs序題目練習


參考博文: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中...

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM