Point divide and conquer template entry learning

Reference video: Video

Reference blog: Blog

Point divide and conquer is a kind of tree divide and conquer, is a powerful weapon to deal with the problem of the path on a large-scale tree

Another kind of tree divide and conquer is divide and conquer, a little more troublesome, almost all points divide and conquer can divide and conquer

 

There are two paths on a tree: through the root node and without the root node

If we delete the root node, we can generate several subtrees with the son of the original root node as the root node

The subtree is divided into: through the root node and without the root node

 

Point divide and conquer algorithm steps:

1. Process the current path through the root node

2. Delete the root node

3. Generate each subtree and repeat steps 1. and 2.

Speaking of which, you probably know why every time you want to focus on the subtree

As for how to find the center of gravity, Baidu, I will not repeat them here

As for how to statistically merge the subtrees and count the answers, there is generally another algorithm, such as a tree array, or a line segment tree, with reversible (because there is a delete root point operation)

 

Let ’s take a look at a question and post a basic template

P4178

Given a tree of n nodes, each edge has an edge weight, and find the number of point pairs whose distance between two points on the tree is less than or equal to 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;
}

 

Published 519 original articles · praised 69 · 50,000+ views

Guess you like

Origin blog.csdn.net/qq_41286356/article/details/105469973