zoukankan      html  css  js  c++  java
  • [点分治]luogu P3806 【模板】点分治1

    题目描述

    给定一棵有n个点的树

    询问树上距离为k的点对是否存在。

    输入输出格式

    输入格式:

    n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径

    接下来m行每行询问一个K

    输出格式:

    对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号)

    输入输出样例

    输入样例
    2 1
    1 2 2
    2
    输出样例
    AYE

    说明

    对于30%的数据n<=100

    对于60%的数据n<=1000,m<=50

    对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000

    分析

    其实点分治的主体思想也就是对于树的重心进行分治,也就是找到重心以后,再找子树的重心,这样效率最大化

    分治的内容千变万化,只有熟练才能分析出来(常用的有容斥原理)

    #include <iostream> 
    #include <cstdio>
    using namespace std;
    const int N=1e5+10;
    struct Edge {
        int u,v,w,nx;
    }g[N];
    int list[N],cnt;
    int sz[N],bg[N],rt,p[N],pcnt,cd[10000010],d[N];
    bool b[N];
    int n,m;
    
    void Add(int u,int v,int w) {
        g[++cnt]=(Edge){u,v,w,list[u]};list[u]=cnt;
    }
    
    void Get_Root(int u,int fa) {
        sz[u]=1;bg[u]=0;
        for (int i=list[u];i;i=g[i].nx)
            if (g[i].v!=fa&&!b[g[i].v]) {
                Get_Root(g[i].v,u);
                sz[u]+=sz[g[i].v];
                bg[u]=max(bg[u],sz[g[i].v]);
            }
        bg[u]=max(bg[u],n-bg[u]);
        if (bg[u]<bg[rt]) rt=u;
    }
    
    void Get_Dist(int u,int fa,int len) {
        p[++pcnt]=len;
        for (int i=list[u];i;i=g[i].nx) 
            if (g[i].v!=fa&&!b[g[i].v]) Get_Dist(g[i].v,u,len+g[i].w);
    }
    
    void Calc(int u,int len,int add) {
        pcnt=0;
        Get_Dist(u,0,len);
        for (int i=2;i<=pcnt;i++)
            for (int j=1;j<i;j++) cd[p[i]+p[j]]+=add;
    }
    
    void Solve(int u) {
        b[u]=1;
        Calc(u,0,1);
        for (int i=list[u];i;i=g[i].nx)
            if (!b[g[i].v]) {
                Calc(g[i].v,g[i].w,-1);
                rt=0;Get_Root(g[i].v,u);
                Solve(rt);
            }
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1,u,v,w;i<n;i++) scanf("%d%d%d",&u,&v,&w),Add(u,v,w),Add(v,u,w);
        bg[0]=2147483647;
        Get_Root(1,0);
        Solve(rt);
        for (int i=1,k;i<=m;i++) {
            scanf("%d",&k);
            printf(!cd[k]?"NAY
    ":"AYE
    ");
        }
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    回归,随缘写一些python心得吧
    划分树【有些东西,其实自己还不太会也要忍住把*装完】
    [codevs3273]两圆的交 计算几何
    10-12考试整理
    10-7考试整理
    [codevs1163]访问艺术馆
    [codevs2640]打印页数
    9-28 解题报告
    [CODEVS3323]时空跳跃者的封锁
    [codevs2442] kshort 经典题
  • 原文地址:https://www.cnblogs.com/mastervan/p/10208219.html
Copyright © 2011-2022 走看看