DFS序 及 手动扩栈指令

概念

DFS序是转树型结构为线型结构的经典方法。


具体实现网上优秀博客很多,就不赘述了…
因为涉及DFS,同时此类题普遍节点的规模都在1e5以上,而HDOJ好像是基于Windows的服务器,很容易爆栈,故我们需要添加一个手动扩栈指令,并用C++提交。

#pragma comment(linker, “/STACK:1024000000,1024000000”)


经典题

HDOJ 3887

题意很简单,但思路却困了我很久,一直纠结于如何解决不同子树相互影响的问题。
但其实由DFS序的性质,假设存在某一个节点X

当搜索到X时,之前搜索到的节点一定不属于X的子树,此时我们用树状数组维护此前出现过的节点的标号,然后查询小于X的标号的节点数量 num_1

当搜索完X的子节点后,树状数组里面会包含X的succeeding nodes即后继节点的信息,再查询小于X的标号的节点数量num_2

然后易得: F[X] = num_2 - num_1

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define lson rt<<1
#define rson rt<<1|1

const int A = 1e5 + 10;
class BIT{
public:
    int c[A];
    void init(){
        memset(c,0,sizeof(c));
    }
    void update(int pos,int val){
        for(int i=pos ;i0 ;i-=(i&(-i))) res+=c[i];
        return res;
    }
}bit;
class P{
public:
    int v,next;
}G[A<<1];
int tot,Rank,head[A],Ans[A];

inline void init(){
    memset(head,-1,sizeof(head));
    tot = Rank = 0;
    bit.init();
}

inline void add(int u,int v){
    G[tot].v = v;
    G[tot].next = head[u];
    head[u] = tot++;
}

void dfs(int u,int pre){
    int num1 = bit.query(u);
    for(int i=head[u] ;i!=-1 ;i=G[i].next){
        int v = G[i].v;
        if(v == pre) continue;
        dfs(v,u);
    }
    int num2 = bit.query(u);
    Ans[u] = num2 - num1;
    bit.update(u,1);
}

int main(){
    int n,p;
    while(~scanf("%d%d",&n,&p)){
        if(!n && !p) break;
        init();
        for(int i=1 ;i

HDOJ 5692

此题因为写错了一个小细节WA了十几发qwq

此题是DFS序结合线段树的经典题,即当线段树维护的不再是一个线性结构而变成树形结构时,我们需要DFS序来进行转换。

理解清DFS序的概念此题便很简单了

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include 
#include
#include 
#include 
#include
#include 
#include 
#include 
#include 
#include
#include
#include
using namespace std;
typedef long long ll;
#define lson rt<<1
#define rson rt<<1|1

const ll INF = 1e18;
const int A = 1e5 + 10;
class P{
public:
    int l,r;
    ll Max,mark;
}Tree[A<<2];
class Node{
public:
    int v,next;
}G[A<<1];
int in[A],out[A],head[A],ID[A];
int tot,Rank;
int n,m;
ll dis[A],a[A];

void init(){
    tot = Rank = 0;
    memset(head,-1,sizeof(head));
}

void add(int u,int v){
    G[tot].v = v;
    G[tot].next = head[u];
    head[u] = tot++;
}

void dfs(int u,int pre){
    in[u] = ++Rank;
    ID[Rank] = u;
    for(int i=head[u] ;i!=-1 ;i=G[i].next){
        int v = G[i].v;
        if(v == pre) continue;
        dis[v] = dis[u] + a[v];
        //printf("dis[%d] = %d\n",v,dis[v]);
        dfs(v,u);
    }
    out[u] = Rank;
}

void push_up(int rt){
    Tree[rt].Max = max(Tree[lson].Max,Tree[rson].Max);
}

void push_down(int rt){
    if(Tree[rt].mark){
        Tree[lson].mark += Tree[rt].mark;
        Tree[rson].mark += Tree[rt].mark;
        Tree[lson].Max += Tree[rt].mark;
        Tree[rson].Max += Tree[rt].mark;
        Tree[rt].mark = 0;
    }
}

void build_Tree(int rt,int l,int r){
    Tree[rt].l = l,Tree[rt].r = r;
    Tree[rt].mark = 0;
    if(l == r){
        Tree[rt].Max = dis[ID[l]];
        return;
    }
    int mid = (l+r)>>1;
    build_Tree(lson,l,mid);
    build_Tree(rson,mid+1,r);
    push_up(rt);
}

void update(int rt,int st,int ed,ll c){
    int l = Tree[rt].l,r = Tree[rt].r;
    if(st<=l && r<=ed){
        Tree[rt].Max += c;
        Tree[rt].mark += c;
        return;
    }
    push_down(rt);
    int mid = (l+r)>>1;
    if(st<=mid) update(lson,st,ed,c);
    if(ed> mid) update(rson,st,ed,c);
    push_up(rt);
}

ll query(int rt,int st,int ed){
    int l = Tree[rt].l,r = Tree[rt].r;
    if(st<=l && r<=ed){
        return Tree[rt].Max;
    }
    push_down(rt);
    int mid = (l+r)>>1;
    ll res = -INF;
    if(st<=mid) res = max(res,query(lson,st,ed));
    if(ed> mid) res = max(res,query(rson,st,ed));
    return res;
}

int main(){
    //freopen("input","r",stdin);
    int T,_=1;
    scanf("%d",&T);
    while(T--){
        printf("Case #%d:\n",_++);
        init();
        scanf("%d%d",&n,&m);
        for(int i=0 ;i

你可能感兴趣的:(DFS序 及 手动扩栈指令)