P3806 【模板】点分治1

本文介绍了一种针对树状结构数据的优化算法,用于快速判断树上是否存在两点间距离等于特定值k的点对。通过寻找树的重心并递归处理子树,结合深度优先搜索(DFS),有效地统计所有可能的点对距离,并通过巧妙地消除重复路径的影响,最终实现O(n^2)的时间复杂度收集答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

\(\color{#0066ff}{题目描述}\)

给定一棵有n个点的树

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

\(\color{#0066ff}{输入格式}\)

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

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

\(\color{#0066ff}{输出格式}\)

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

\(\color{#0066ff}{输入样例}\)

2 1
1 2 2
2

\(\color{#0066ff}{输出样例}\)

AYE

\(\color{#0066ff}{数据范围与提示}\)

对于30%的数据n<=100

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

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

\(\color{#0066ff}{题解}\)

每次找重心,删去递归子树
对于每个子树,dfs出到子树根(重心)的距离
对于同一子树的,会有重复的路径,那不是答案,但是也统计了,所以在枚举孩子的时候要减回去,这部分答案在递归子树的时候会被统计
每次把所有的子树的dis扔进数组里
\(O(n^2)收集答案\)
#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL in() {
    char ch; int x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
struct node {
    int to, dis;
    node *nxt;
    node(int to = 0, int dis = 0, node *nxt = NULL): to(to), dis(dis), nxt(nxt) {}
    void *operator new (size_t) {
        static node *S = NULL, *T = NULL;
        return (S == T) && (T = (S = new node[1024]) + 1024), S++;
    }
};
const int maxn = 2e5 + 10;
int f[maxn], tmp[maxn], dis[maxn], siz[maxn], can[maxn];
bool vis[maxn];
node *head[maxn];
int n, sum, m, root, num;

void add(int from, int to, int dis) {
    head[from] = new node(to, dis, head[from]);
}
void getdis(int x, int fa, int d) {
    tmp[++num] = d;
    dis[x] = d;
    for(node *i = head[x]; i; i = i->nxt)
        if(i->to != fa && !vis[i->to]) 
            getdis(i->to, x, d + i->dis);
}
void calc(int x, int d, int flag) {
    num = 0;
    dis[x] = d;
    getdis(x, 0, dis[x]);
    for(int i = 1; i <= num; i++)
        for(int j = 1; j <= num; j++)
            if(i != j)
                can[tmp[i] + tmp[j]] += flag;
}
void getroot(int x, int fa) {
    siz[x] = 1;
    f[x] = 0;
    for(node *i = head[x]; i; i = i->nxt) {
        if(i->to == fa || vis[i->to]) continue;
        getroot(i->to, x);
        siz[x] += siz[i->to];
        f[x] = std::max(f[x], siz[i->to]);
    }
    f[x] = std::max(f[x], sum - siz[x]);
    if(f[x] < f[root]) root = x;
}

void work(int x) {
    calc(x, 0, 1);
    vis[x] = true;
    for(node *i = head[x]; i; i = i->nxt) 
        if(!vis[i->to]) {
            calc(i->to, i->dis, -1);
            sum = siz[i->to];
            root = 0;
            getroot(i->to, 0);
            work(root);
        }
}

int main() {
    n = in(), m = in();
    int x, y, z;
    for(int i = 1; i <= n - 1; i++) {
        x = in(), y = in(), z = in();
        add(x, y, z), add(y, x, z);
    }
    f[0] = n, sum = n;
    getroot(1, 0), work(root);
    while(m --> 0) printf(can[in()]? "AYE\n" : "NAY\n");
    return 0;
}

转载于:https://www.cnblogs.com/olinr/p/10206208.html

p1177是《算法导论》(Introduction to Algorithms)这本书中的个问题编号,它通常指的是书中关于排序算法的内容。在这本书中,排序算法是个核心主题,其中包括许多经典算法如冒泡排序、插入排序、选择排序、希尔排序、归并排序、快速排序等。 具体到P1177,可能会涉及到某个特定排序算法的描述、分析其时间复杂度、实现细节或者是比较不同排序算法的优缺。例如,快速排序在该页可能会有详细的递归实现讲解,而归并排序则可能涉及分治策略和合并过程。 如果你需要了解某种排序算法的具体步骤或者代码模板,比如“如何用C语言实现快速排序”,这里可以给你个简单的快速排序的C语言模板: ```c #include <stdio.h> void swap(int* a, int* b) { int t = *a; *a = *b; *b = t; } int partition(int arr[], int low, int high) { int pivot = arr[high]; int i = (low - 1); for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1); } void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } // 示例 int main() { int arr[] = {10, 7, 8, 9, 1, 5}; int n = sizeof(arr) / sizeof(arr[0]); quickSort(arr, 0, n - 1); printf("Sorted array: \n"); for (int i=0; i < n; i++) printf("%d ", arr[i]); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值