Aprendizagem de entrada de modelo de divisão e conquista de pontos

Vídeo de referência: Vídeo

Blog de referência: Blog

A divisão e conquista de pontos é um tipo de divisão e conquista de árvores, é uma arma poderosa para lidar com o problema do caminho em uma árvore em grande escala

Outro tipo de divisão e conquista de árvores é dividir e conquistar, um pouco mais problemático, quase todos os pontos divididos e conquistados podem dividir e conquistar

 

Existem dois caminhos em uma árvore: através do nó raiz e sem o nó raiz

Se excluirmos o nó raiz, podemos gerar várias subárvores com o filho do nó raiz original como o nó raiz

A subárvore é dividida em: através do nó raiz e sem o nó raiz

 

Etapas do algoritmo de divisão e conquista de pontos:

1. Processe o caminho atual através do nó raiz

2. Exclua o nó raiz

3. Gere cada subárvore e repita as etapas 1. e 2.

Por falar nisso, você provavelmente sabe por que sempre que deseja se concentrar na subárvore

Quanto a como encontrar o centro de gravidade, Baidu, não vou repeti-los aqui

Quanto a como mesclar estatisticamente as subárvores e contar as respostas, geralmente existe outro algoritmo, como uma matriz em árvore ou uma árvore de segmentos de linha, com reversibilidade (porque existe uma operação de exclusão do ponto raiz)

 

Vamos dar uma olhada em uma pergunta e postar um modelo básico

P4178

Dada uma árvore de n nós, cada aresta tem um peso de aresta e encontre o número de pares de pontos cuja distância entre dois pontos na árvore é menor ou igual a k.

include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=262144;
const int INF=1<<29;

int n,m;

struct Edge{
    int next,to,w;
}e[MAXN<<1];
int ecnt,head[MAXN];
inline void add(int x,int y,int w){
    e[++ecnt].next = head[x];
    e[ecnt].to = y;
    e[ecnt].w = w;
    head[x] = ecnt;
}

int t[MAXN];
void update(int x,int val){
    for(int i=x;i<=m;i+=i&-i)t[i]+=val;
}
int query(int x){
    if(x==0) return 0;
    int ret=0;
    for(int i=x;i;i-=i&-i)ret+=t[i];
    return ret;
}

bool vis[MAXN];

int siz[MAXN];
void getsiz(int x,int pre){//预处理树上  每个节点的子树大小 
    siz[x]=1;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]||v==pre) continue;
        getsiz(v,x);
        siz[x]+=siz[v];
    }
}
int mn=INF,root;
void getroot(int x,int pre,int tot){
    int mx=0;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]||v==pre) continue;
        mx=max(mx,siz[v]);
        getroot(v,x,tot);
    }
    mx=max(mx,tot-siz[x]);
    if(mx<mn) mn=mx,root=x;
}
int s[MAXN],sav[MAXN];

void dfs(int x,int pre,int dis){
    if(dis>m) return;
    s[++s[0]]=dis;
	sav[++sav[0]]=dis;
	
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]||v==pre) continue;
        dfs(v,x,dis+e[i].w);
    }
}

int ans;

void dac(int x){//Divide and Conquer :)
    sav[0]=0;mn=n;
    
    
    getsiz(x,-1);//以x为根节点  重新getsize  一下  
    getroot(x,-1,siz[x]);//先找到一个重心 
    
    
    
    int u=root;vis[u]=1;///删掉根节点 
    for(int i=head[u];i;i=e[i].next){//维护答案 
        int v=e[i].to;
        if(vis[v]) continue;
        s[0]=0;
		dfs(v,u,e[i].w); //以u节点为根的   经过根节点的路径保存至s 和  sav里面 
        for(int j=s[0];j>=1;j--){
            if(s[j]>m) continue;
            ans+=query(m-s[j]);//权值树状数组 
        }
        
        
        for(int j=s[0];j>=1;j--){
            if(s[j]>m) continue;
            update(s[j],1);//更新答案 
            ans++;
        }
    }
    
    
    
    for(int i=sav[0];i>=1;i--){//删掉答案 
        if(sav[i]>m) continue;
        update(sav[i],-1);
    }
    
    
    for(int i=head[u];i;i=e[i].next){//去掉根u  继续点分治 
        int v=e[i].to;
        if(vis[v]) continue;
        dac(v);
    }
}



int main(){
    n=rd();
    int x,y,w;
    for(int i=1;i<n;i++){
        x=rd();y=rd();w=rd();
        add(x,y,w);add(y,x,w);
    }
    m=rd();
    
    dac(1);
    cout<<ans;
    return 0;
}

 

Publicado 519 artigos originais · elogiou 69 · 50.000+ visualizações

Acho que você gosta

Origin blog.csdn.net/qq_41286356/article/details/105469973
Recomendado
Clasificación