【提醒后人】线段树合并

CF1009F Dominant Indices

Biuld @ 2023-10-12 07:53:17

如果你不管怎么调都是 RE 或是 MLE 的话,我的建议是:特判个链,别调了
太折磨了这,没必要(也不知道为什么链空间会炸掉
当然,如果能有稳过的线段树合并方法,麻烦踹一下我,谢谢


by Saka_Noa @ 2023-10-12 08:05:34

#include <bits/stdc++.h>
using namespace std;
#define _ (int)(1e6 + 5)
#define lc ls[k]
#define rc rs[k]
#define lcon lc, l, mid
#define rcon rc, mid + 1, r
#define Mid int mid = ((l + r) >> 1)
#define InitO int &k, int l, int r
#define InitT int k, int l, int r
#define FR for (int i = head[u], v = e[i].to; i; i = e[i].next, v = e[i].to)
#define For(i, a, b) for (int i = a; i <= b; i++)
int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0', ch = getchar();
    }
    return x * f;
}
void write(int x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

struct edge
{
    int next, to;
} e[_ << 1];
struct node
{
    int id, val;
    node() { id = val = 0; }
} tree[_ << 2];

int n, cnt, cot, top;
int head[_], dep[_], ls[_ << 2], rs[_ << 2], root[_], ans[_], stac[_ << 2];

int NewNode()
{
    if (top)
        return stac[top--];
    else
        return ++cot;
}
void add(int f, int t)
{
    e[++cnt] = edge{head[f], t};
    head[f] = cnt;
}

void dfs(int u, int f)
{
    dep[u] = dep[f] + 1;
    FR
    {
        if (v == f)
            continue;
        dfs(v, u);
    }
}
node pushup(node a, node b)
{
    if (!a.id)
        return b;
    if (!b.id)
        return a;
    if (a.val == b.val)
        return a.id < b.id ? a : b;
    else
        return a.val > b.val ? a : b;
}
void update(InitO, int x, int v)
{
    if (!k)
        k = NewNode();
    if (l == r)
        return (void)(tree[k].val += v, tree[k].id = x);
    Mid;
    if (x <= mid)
        update(lcon, x, v);
    else
        update(rcon, x, v);
    tree[k] = pushup(tree[lc], tree[rc]);
}
node query(InitT, int x, int y)
{
    if (!k)
        return node();
    if (x <= l && r <= y)
        return tree[k];
    Mid;
    node ans;
    if (x <= mid)
        ans = query(lcon, x, y);
    if (y > mid)
        ans = pushup(ans, query(rcon, x, y));
    return ans;
}
int merge(int a, int b, int l, int r)
{
    if (!a || !b)
        return a + b;
    if (l == r)
    {
        tree[a].val += tree[b].val;
        tree[b].id = tree[b].val = ls[b] = rs[b] = 0;
        stac[++top] = b;
        return a;
    }
    Mid;
    ls[a] = merge(ls[a], ls[b], l, mid);
    rs[a] = merge(rs[a], rs[b], mid + 1, r);
    tree[a] = pushup(tree[ls[a]], tree[rs[a]]);
    tree[b].id = tree[b].val = ls[b] = rs[b] = 0;
    stac[++top] = b;
    return a;
}

void dfs2(int u, int f)
{
    FR
    {
        if (v == f)
            continue;
        dfs2(v, u);
        root[u] = merge(root[u], root[v], 1, _);
    }
    update(root[u], 1, _, dep[u], 1);
    node c = query(root[u], 1, _, 1, _);
    ans[u] = c.id - dep[u];
}
int main()
{
    n = read();
    For(i, 1, n - 1)
    {
        int u, v;
        u = read();
        v = read();
        add(u, v);
        add(v, u);
    }
    dfs(1, 0);
    dfs2(1, 0);
    For(i, 1, n) write(ans[i]), puts("");
    return 0;
}

这份应该没判吧,我之前写的代码


by Biuld @ 2023-10-12 21:04:13

@Saka_Noa 感谢,对照了您的代码后,现在终于知道问题出在哪了


by Biuld @ 2023-10-12 21:06:26

在我线段树合并的 Dfs 中


inline void Dfs1(int now, int fath){
    dep[now] = dep[fath] + 1;
//  rt[now] = update(rt[now], 1, n, dep[now]);
    for(int i = head[now]; i; i = e[i].nxt){
        int v = e[i].to;

        if(v != fath){
            Dfs1(v, now);
            rt[now] = merge(rt[now], rt[v], 1, n);
        }
    }
    rt[now] = update(rt[now], 1, n, dep[now]);
    ans[now] = query(rt[now], 1, n) - dep[now];
}

update 本来是写在上面的,为先开新点再回收旧店,导致空间回收的效果微乎其微。
正确做法应是 update 新开点写在 merge 回收旧点后


by Cubic @ 2023-10-12 22:07:09

膜拜。


|