ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

观察

2021-09-04 23:04:13  阅读:174  来源: 互联网

标签:return int read 棋子 LCA 观察 节点


题目大意

给出一颗以 \(1\) 为根且有 \(n\) 个节点的树,一开始每个节点都是一颗棋子,一面白一面黑,白色的面朝上。

接下来就 \(q\) 次操作,操作分两种:

  • \(0\) 操作,将一颗棋子翻转。
  • \(1\) 操作,询问一颗棋子与所有面朝上为黑色的棋子的 LCA 最深LCA 的编号(若当前没有黑棋子输出 \(0\))。

对于 \(100 \%\) 的数据,\(1 ≤ n ≤ 800000\), \(1 ≤ q ≤ 800000\)。

解题思路

思路应该算是比较好想的了。

用树状数组或线段树加树剖维护子树内黑色朝上的棋子的个数。

对于操作 \(0\),非常简单,不讲了。

对于操作 \(1\),每次类似于树剖跳链,不同的是一直跳父亲,判断当前跳到的节点的子树内是否有黑棋,有就直接输出。(这样做的理由是,一个节点与另一个节点的 LCA 只可能存在于两个节点中任意一个节点到根节点的简单路径上)

注意,本题数据过大,可能会爆栈,可以吸氧。

AC CODE

#include <bits/stdc++.h>
#define _ (int)800000 + 5
using namespace std;

int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}

int n, m;

int fa[_];

int a[_];

bool tag[_];

int tot, head[_], to[_ << 1], nxt[_ << 1];

int cnt_node, siz[_], dfn[_], hson[_];

void add(int u, int v)
{
    to[++tot] = v;
    nxt[tot] = head[u];
    head[u] = tot;
}

void dfs1(int u)
{
    siz[u] = 1;
    for (int i = head[u]; i; i = nxt[i])
    {
        int v = to[i];
        if (siz[v])
            continue;
        dfs1(v);
        siz[u] += siz[v];
        if (siz[hson[u]] < siz[v])
            hson[u] = v;
    }
}

void dfs2(int u)
{
    dfn[u] = ++cnt_node;
    if (!hson[u])
        return;
    dfs2(hson[u]);
    for (int i = head[u]; i; i = nxt[i])
    {
        int v = to[i];
        if (!dfn[v])
            dfs2(v);
    }
}

void update(int x)
{
    int y = 1;
    if (tag[x])
        y = -1;
    tag[x] ^= 1;
    for (int i = x; i <= n; i += i & -i)
        a[i] += y;
}

int query(int x)
{
    int res = 0;
    for (int i = x; i > 0; i -= i & -i)
        res += a[i];
    return res;
}

bool Query(int x)
{
    return query(dfn[x] + siz[x] - 1) - query(dfn[x] - 1);
}

int solve(int x)
{
    while (x)
    {
        if (Query(x))
            return x;
        x = fa[x];
    }
    return 0;
}

signed main()
{
    n = read();
    m = read();
    for (int i = 2; i <= n; ++i)
    {
        fa[i] = read();
        add(fa[i], i);
        add(i, fa[i]);
    }
    dfs1(1);
    dfs2(1);
    for (int i = 1; i <= m; ++i)
    {
        int x;
        x = read();
        if (x > 0)
        {
            update(dfn[x]);
        }
        else
        {
            printf("%d\n", solve(-x));
        }
    }
    return 0;
}

标签:return,int,read,棋子,LCA,观察,节点
来源: https://www.cnblogs.com/orzz/p/15228109.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有