洛谷 P3806 【模板】点分治1

题目传送门

点分治:我的理解就是对树进行分治,再对这棵树的每棵子树进行分治,一直这样下去,当然树的根不是随便都可以的,以树的重心为根,复杂度会大大降低(个人拙见)。

代码:

#include<bits/stdc++.h>
using namespace std;

const int INF=0x3f3f3f3f;
const int maxn=10000+100;
const int maxm=10000000+100;

bool kaven[maxm],vis[maxn];
struct Edge{

    int to,len,next;
}edge[maxn<<1];
int head[maxn],tot;
int son[maxn],dis[maxn];
int root,all,num;
int n,m;
struct Node{

    int id,dis;
}node[maxn];
int Id,nodenum;

void Add(int u,int v,int len){

    edge[tot].to=v;
    edge[tot].len=len;
    edge[tot].next=head[u];
    head[u]=tot++;

    edge[tot].to=u;
    edge[tot].len=len;
    edge[tot].next=head[v];
    head[v]=tot++;
}
//得到目前这棵树的重心
void DFS(int u,int fa){

    son[u]=1;
    int maxson=0;
    for(int i=head[u];i!=-1;i=edge[i].next){

        Edge e=edge[i];
        int v=e.to;
        if(v==fa || vis[v]) continue;
        son[u]+=son[v];
        maxson=max(maxson,son[v]);
    }
    maxson=max(maxson,all-son[u]);
    if(maxson<num) root=u,num=maxson;
}

//计算结点到当前树 root 的距离 (以前进行过点分治的除外,不然会有大量重复计算) 
void getDis(int rot,int u,int fa,int id){

    for(int i=head[u];i!=-1;i=edge[i].next){

        Edge e=edge[i];
        int v=e.to,len=e.len;
        if(vis[v] || v==fa) continue;
        dis[v]=dis[u]+len;
        if(rot==u) node[nodenum].dis=dis[v],node[nodenum++].id= ++Id;  //root的孩子结点是 root这棵树的子树的根,所以++Id 对子树根进行编号 
        else node[nodenum].dis=dis[v],node[nodenum++].id= id;   //子树非根结点编号为子树根结点的编号 
        kaven[dis[v]]=true;
        if(rot==u) getDis(rot,v,u,Id);
        else getDis(rot,v,u,id);
    }
}

//点分治 
void getNode(int u){

    dis[u]=0;
    vis[u]=true;
    Id=nodenum=0;  //Id:对树根为 root 的每棵子树进行编号(以前进行过点分治的除外),在同一棵子树上的结点编号相同 
    getDis(root,u,-1,0); 
    for(int i=0;i<nodenum;i++){

        for(int j=i+1;j<nodenum;j++){

            if(node[i].id!=node[j].id) kaven[node[i].dis+node[j].dis]=true;   //不同子树结点之间的距离 
        }
    }
    for(int i=head[u];i!=-1;i=edge[i].next){

        Edge e=edge[i];
        int v=e.to;
        if(vis[v]) continue;
        root=0;all=son[v];num=INF;  //初始化  
        DFS(v,-1);         //找子树的重心 
        getNode(root);     //子树进行点分治
    }
}

int main(){

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) head[i]=-1;
    tot=0;root=0;num=INF;all=n;
    for(int i=1;i<n;i++){

        int u,v,len;
        scanf("%d%d%d",&u,&v,&len);
        Add(u,v,len);
    }
    DFS(1,-1);
    getNode(root);
    for(int i=1,k;i<=m;i++) scanf("%d",&k),printf("%s\n",kaven[k]?"AYE":"NAY");
}

猜你喜欢

转载自blog.csdn.net/qq_37960603/article/details/81533338
今日推荐