[POJ 1316] 树上的询问

[题目链接]

https://www.lydsy.com/JudgeOnline/problem.php?id=1316

[算法]

点分治

由于边权较大,笔者在计算时使用了STL-set

注意当询问为0时,要输出"Yes"

[代码]

#include<bits/stdc++.h>
using namespace std;
#define MAXN 10010
#define MAXQ 110

struct Edge
{
    int to,w,nxt;
} e[MAXN<<1];

int i,n,q,tot,root,u,v,w,len;
int size[MAXN],head[MAXN],weight[MAXN],sum[MAXN],val[MAXN],a[MAXQ];
bool visited[MAXN],ans[MAXQ];

inline void addedge(int u,int v,int w)
{
    tot++;
    e[tot] = (Edge){v,w,head[u]};
    head[u] = tot;
}
inline void getroot(int u,int fa,int total)
{
    int i,v;
    size[u] = 1;
    weight[u] = 0;
    for (i = head[u]; i; i = e[i].nxt)
    {
        v = e[i].to;
        if (fa != v && !visited[v])
        {
            getroot(v,u,total);
            size[u] += size[v];
            weight[u] = max(weight[u],size[v]);
        }
    }
    weight[u] = max(weight[u],total - size[u]);
    if (weight[u] < weight[root]) root = u;
}
inline void dfs(int u,int fa)
{
    int i,v,w;
    val[++len] = sum[u];
    for (i = head[u]; i; i = e[i].nxt)
    {
        v = e[i].to;
        w = e[i].w;
        if (v != fa && !visited[v])
        {
            sum[v] = sum[u] + w;
            dfs(v,u);
        }
    }
}
inline void calc(int u)
{
    int i,j,k,v,w;
    set< int > s;
    s.clear();
    s.insert(0);
    for (i = head[u]; i; i = e[i].nxt)
    {
        v = e[i].to;
        w = e[i].w;
        if (!visited[v])
        {
            sum[v] = w;
            len = 0;
            dfs(v,u);
            for (j = 1; j <= len; j++)
            {
                for (k = 1; k <= q; k++)
                {
                    if (s.find(a[k] - val[j]) != s.end())
                        ans[k] = true;
                }
            }
            for (j = 1; j <= len; j++) s.insert(val[j]);
        }
    }
}
inline void work(int u)
{
    int i,v;
    visited[u] = true;
    calc(u);
    for (i = head[u]; i; i = e[i].nxt)
    {
        v = e[i].to;
        if (!visited[v])
        {
            root = 0;
            getroot(v,0,size[v]);
            work(root);
        }
    }
}

int main()
{

    scanf("%d%d",&n,&q);
    for (i = 1; i < n; i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w);
        addedge(v,u,w);
    }
    for (i = 1; i <= q; i++) scanf("%d",&a[i]);
    root = 0;
    size[0] = weight[0] = n;
    getroot(1,0,n);
    work(root);
    for (i = 1; i <= q; i++) printf((ans[i] || a[i] == 0) ? "Yes\n" : "No\n");

    return 0;
}

原文地址:https://www.cnblogs.com/evenbao/p/9328402.html

时间: 2024-10-14 00:42:57

[POJ 1316] 树上的询问的相关文章

BZOJ 1316: 树上的询问 (点分治+set)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1316 因为只要求存在某条路径长度为K,所以点分,然后用set判断差值是否在set中就可以了. #include<cstring>#include<algorithm>#include<iostream>#include<cstdio>#include<queue>#include<set>#include<cmath>

【BZOJ1316】树上的询问 点分治+set

[BZOJ1316]树上的询问 Description 一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. Input 第一行两个整数n, p分别表示点的个数和询问的个数. 接下来n-1行每行三个数x, y, c,表示有一条树边x→y,长度为c. 接下来p行每行一个数Len,表示询问树中是否存在一条长度为Len的路径. Output 输出有p行,Yes或No. Sample Input 6 4 1 2 5 1 3 7 1 4 1 3 5

[bzoj1316]树上的询问_点分治

树上的询问 bzoj-1316 题目大意:一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. 注释:$1\le n\le 10^4$,$1\le p\le 100$,长度$\le 10^6$. 想法:有根树tm是啥意思?根在jb哪呢?老子我瞅tm这么半天也没看见根在哪呢??这题点分治即可.我们用点分治的第二种:分别计算子树,然后用之前的信息更新答案.对于此题,我们可以直接维护一个set就行. 最后,附上丑陋的代码... ... #inc

POJ 1316 Self Numbers

题目链接: http://poj.org/problem?id=1316 Description In 1949 the Indian mathematician D.R. Kaprekar discovered a class of numbers called self-numbers. For any positive integer n, define d(n) to be n plus the sum of the digits of n. (The d stands for digi

NKOJ P3815 树上的询问 (LCA 倍增)(复习距离倍增)

评测说明 : 1000ms 问题描述 现有一棵 n 个节点的树,树上每条边的长度均为 1.给出 m 个询问,每次询问两个节 点 x,y,求树上到 x,y 两个点距离相同的节点数量. 输入格式 第一个整数 n,表示树有 n 个点. 接下来 n-1 行每行两整数 a,b,表示从 a 到 b 有一条边. 接下来一行一个整数 m,表示有 m 个询问. 接下来 m 行每行两整数 x,y,询问到 x 和 y 距离相同的点的数量. 输出格式 共 m 行,每行一个整数表示询问的答案. 样例输入 7 1 2 1 

cqyz oj | 树上的询问 | 最近公共祖先

Description 现有一棵 n 个节点的棵, 树上每条边的长度均为 1. 给出 m 个询问, 每次询问两个节点 x,y, 求树上到 x,y 两个点距离相同的节点数量. Input 第一个整数 n, 表示树有 n 个点. 接下来 n-1 行每行两整数 a, b, 表示从 a 到 b 有一条边. 接下来一行一个整数 m, 表示有 m 个询问. 接下来 m 行每行两整数 x, y, 询问到 x 和 y 距离相同的点的数量. Output 共 m 行, 每行一个整数表示询问的答案. Sample

ac自动机fail树上按询问建立上跳指针——cf963D

解法看着吓人,其实就是为了优化ac自动机上暴力跳fail指针.. 另外这题对于复杂度的分析很有学习价值 /* 给定一个母串s,再给定n个询问(k,m) 对于每个询问,求出长度最小的t,使t是s的子串,且m作为子串在t中出现了m次 对多串建立ac自动机,然后用s去匹配,把所有询问的出现位置都用vector保存下来 然后对应每个询问的k进行更新答案 为了保证复杂度:在跳fail不能暴力向上跳,应该直接用一个指针pre跳到上一个带有询问的点 这样每次向上跳都让某个询问的vector更新进一个新的值 由

[bzoj1316] 树上的询问

裸的点分治.. 及时把已经确定的询问清掉就能快不少.时间复杂度O(nlogn*p) 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=10023; 7 struct zs{int len,id;bool done;}q[103]; 8 struct zs1{int t

【bzoj1316】树上的询问 树的点分治+STL-set

题目描述 一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. 输入 第一行两个整数n, p分别表示点的个数和询问的个数. 接下来n-1行每行三个数x, y, c,表示有一条树边x→y,长度为c. 接下来p行每行一个数Len,表示询问树中是否存在一条长度为Len的路径. 输出 输出有p行,Yes或No. 样例输入 6 4 1 2 5 1 3 7 1 4 1 3 5 2 3 6 3 1 8 13 14 样例输出 Yes Yes No Yes