点分治4和7wa了

P3806 【模板】点分治 1

RevolutionBP @ 2022-02-24 21:05:38


/*
BlackPink is the Revolution
light up the sky
Blackpink in your area
*/
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
#define rep(i, a, b) for (int i = (a); (i) <= (b); ++i)
#define per(i, a, b) for (int i = (a); (i) >= (b); --i)
#define whlie while
using namespace std;
const int N = 1e7 + 5;
const int K = 1e7 + 5;
typedef long long ll;
typedef pair<int, int> P;

namespace scan {
template <typename T>
inline void read(T& x) {
    x = 0;
    char c = getchar();
    int f = 0;
    for (; !isdigit(c); c = getchar())
        f |= (c == '-');
    for (; isdigit(c); c = getchar())
        x = x * 10 + (c ^ 48);
    if (f)
        x = -x;
}
template <typename T, typename... Args>
inline void read(T& x, Args&... args) {
    read(x), read(args...);
}
template <typename T>
inline void write(T x, char ch) {
    if (x < 0)
        putchar('-'), x = -x;
    static short st[30], tp;
    do
        st[++tp] = x % 10, x /= 10;
    while (x);
    while (tp)
        putchar(st[tp--] | 48);
    putchar(ch);
}
template <typename T>
inline void write(T x) {
    if (x < 0)
        putchar('-'), x = -x;
    static short st[30], tp;
    do
        st[++tp] = x % 10, x /= 10;
    while (x);
    while (tp)
        putchar(st[tp--] | 48);
}

inline void write(char ch) {
    putchar(ch);
}
}  // namespace scan
using namespace scan;
int n, m, cnt, T, sum, sumsiz, rt;
int maxsiz[N], siz[N], head[N], dis[N], ans[N], q[N];
bool vis[N], exist[N];
vector<int> tmp;
queue<int> tag;

struct edge {
    int to, val, nxt;
} e[N << 1];
inline void add(int u, int v, int w) {
    e[++cnt] = (edge){v, w, head[u]};
    head[u] = cnt;
}

inline void CalcSize(int u, int f) {
    siz[u] = 1;
    maxsiz[u] = 0;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (v == f || vis[v])
            continue;
        CalcSize(v, u);
        maxsiz[u] = max(maxsiz[u], siz[v]);
        siz[u] += siz[v];
    }
    maxsiz[u] = max(maxsiz[u], sumsiz - siz[u]);
    if (maxsiz[u] < maxsiz[rt])
        rt = u;
}

void Calc(int u, int f) {
    tmp.push_back(dis[u]);
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to, w = e[i].val;
        if (v == f || vis[v])
            continue;
        dis[v] = dis[u] + w;
        Calc(v, u);
    }
}

inline void Calc2(int u, int f) {
    exist[0] = true;
    tag.push(0);
    vis[u] = true;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to, w = e[i].val;
        if (v == f || vis[v])
            continue;
        dis[v] = w;
        Calc(v, u);
        int sizz = tmp.size() - 1;
        rep(j, 0, sizz)
            rep(k, 1, m) 
                if (q[k] >= tmp[j])
                    ans[k] |= exist[q[k] - tmp[j]];
        rep(j, 0, sizz) {
            if (tmp[j] < K) {
                tag.push(tmp[j]);
                exist[tmp[j]] = true;
            }
        }
        tmp.clear();
    }
    while (!tag.empty())
        exist[tag.front()] = false, tag.pop();
}

inline void dfs(int u, int f) {
    Calc2(u, f);
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (v == f || vis[v])
            continue;
        sumsiz = siz[v];
        rt = 0;
        maxsiz[rt] = N;
        CalcSize(v, u), Calc(rt, 0), dfs(rt, 0);
    }
}

int main() {
    read(n, m);
    rep(i, 1, n - 1) {
        int u, v, w;
        read(u, v, w);
        add(u, v, w);
        add(v, u, w);
    }
    rep(i, 1, m) read(q[i]);
    maxsiz[rt] = N;
    sumsiz = n;
    CalcSize(1, 0);
    Calc(rt, 0);
    dfs(rt, 0);
    rep(i, 1, m) puts(ans[i] ? "AYE" : "NAY");
    return 0;
}
// write:RevolutionBP

by RevolutionBP @ 2022-02-24 21:07:02

说错了,是4和6wa了

代码得分


by LawrenceSivan @ 2022-02-27 20:56:01

@RevolutionBP

我看明白是哪里的问题了。

情况是这样的。

CalcSize(1, 0);
Calc(rt, 0);
dfs(rt, 0);

你每次进行分治的时候,都会首先寻找重心,这个是正确的,但是你之后紧接着进行了一次 Calc 操作,这个操作其实是不必要的,你在 dfs 的过程中就会自然的处理,并不需要你进行这一次 calc ,相反的,由于你进行了这一次 calc 操作,导致你的 tmp 数组每次开始时并不是清零的状态,而是充满了这个点为根的子树的距离值,这也就导致你后面的分治出现了问题


by LawrenceSivan @ 2022-02-27 20:57:12

@RevolutionBP 更改后的提交记录


by LawrenceSivan @ 2022-02-27 20:57:49

@RevolutionBP 为了帮助你理解,我绘制了一些图片,你可以抽空看一下


by LawrenceSivan @ 2022-02-27 21:04:04

@RevolutionBP


by LawrenceSivan @ 2022-02-27 21:06:24

@RevolutionBP 并且对于你的 calc2 函数内,为了防止自己子树内拼接导致路径重复问题,我们要先尝试拼接,再把自己子树内的值加入


by LawrenceSivan @ 2022-02-27 21:09:11

@RevolutionBP

也就是为了避免这种情况


by LawrenceSivan @ 2022-02-27 21:09:48

@RevolutionBP 说的可能啰嗦了点,希望你能看懂。加油!


|