• BZOJ 4551: [Tjoi2016&Heoi2016]树


    4551: [Tjoi2016&Heoi2016]树

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 748  Solved: 394
    [Submit][Status][Discuss]

    Description

    在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下
    两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个
    结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
    先)你能帮帮他吗?

    Input

    输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v
    有一条有向边接下来Q行,形如“opernum”oper为“C”时表示这是一个标记操作,oper为“Q”时表示这是一个询
    问操作对于每次询问操作,1 ≤ N, Q ≤ 100000。

    Output

    输出一个正整数,表示结果

    Sample Input

    5 5
    1 2
    1 3
    2 4
    2 5
    Q 2
    C 2
    Q 2
    Q 5
    Q 3

    Sample Output

    1
    2
    2
    1

    HINT

     新加数据9组(By HFLSyzx ),未重测--2016.8.2

    Source

     
    [Submit][Status][Discuss]

    分析

    先离线读入所有的操作,统计每个点的标记次数,用并查集构建每个点向上最近的标记点。倒序处理操作,如果是查询,直接输出并查集的答案即可;否则该点标记次数减1,如果刚好变成0,就把并查集连向其父亲结点。

    代码

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int N = 200005;
     6 
     7 int n, m;
     8 
     9 int tot;
    10 int hd[N];
    11 int nt[N];
    12 int to[N];
    13 
    14 int ope[N];
    15 int num[N];
    16 int cnt[N];
    17 int ans[N];
    18 
    19 char oper[5];
    20 
    21 int fa[N], f[N];
    22 
    23 int find(int u)
    24 {
    25     return fa[u] == u ? u : fa[u] = find(fa[u]);
    26 }
    27 
    28 void prework(int u, int fr)
    29 {
    30     f[u] = fr;
    31     
    32     if (cnt[u])
    33         fa[u] = u;
    34     else
    35         fa[u] = find(fr);
    36         
    37     for (int i = hd[u]; ~i; i = nt[i])
    38         if (to[i] != fr)prework(to[i], u);
    39 }
    40 
    41 signed main(void)
    42 {
    43     scanf("%d%d", &n, &m);
    44     
    45     memset(hd, -1, sizeof(hd));
    46     
    47     for (int i = 1; i < n; ++i)
    48     {
    49         int x, y; scanf("%d%d", &x, &y);
    50         
    51         nt[tot] = hd[x]; to[tot] = y; hd[x] = tot++;
    52         nt[tot] = hd[y]; to[tot] = x; hd[y] = tot++;
    53     }
    54     
    55     ++cnt[1];
    56     
    57     for (int i = 1; i <= m; ++i)
    58     {
    59         scanf("%s%d", oper, num + i);
    60         
    61         if (oper[0] == 'C')
    62             ope[i] = 1, ++cnt[num[i]];
    63     }
    64     
    65     prework(1, 1);
    66     
    67     for (int i = m; i >= 1; --i)
    68     {
    69         if (ope[i])
    70         {
    71             --cnt[num[i]];
    72             if (!cnt[num[i]])
    73                 fa[num[i]] = find(f[num[i]]);
    74         }
    75         else
    76             ans[i] = find(num[i]);
    77     }
    78     
    79     for (int i = 1; i <= m; ++i)
    80         if (!ope[i])printf("%d
    ", ans[i]);
    81 }
    BZOJ_4551.cpp

    @Author: YouSiki

  • 相关阅读:
    如何修改 gitlab 的项目名称
    Vue 项目中 webSocket 的使用(服务端是 Java Spring boot)
    如何能选到好的车牌号
    实现微信,浏览器,App中H5的路线规划
    H5 navigator.geolocation demo
    npm package.json 中版本指定符号: ~ 、^、*
    小程序中静态资源绝对路径的写法
    重置gvim8 ctrl+f的翻页功能
    [TS]Map的基本操作
    [TS]闭包测试
  • 原文地址:https://www.cnblogs.com/yousiki/p/6091502.html
Copyright © 2020-2023  润新知