• AOJ 2170 Marked Ancestor[并查集][离线]


    题意:

    给你一颗N个节点的树,节点编号1到N。1总是节点的根。现在有两种操作:

    1. M v: 标记节点v
    2. Q v: 求出离v最近的标记的相邻节点。根节点一开始就标记好了。

    现在给一系列操作,求出所有Q操作结果的和。

    思路:

    最坏情况下为整棵树成为一条链,单纯使用并查集(无压缩)查询复杂度最坏1e10。单纯使用并查集也能过。

    正解应该是将查询存下来,存下每次Q操作的查询时间和查询结点,用qt和qv数组存储。另外设置mark数组存储这个结点被染色的最快时间。然后我们倒着进行查询操作,当当前查询的结点最早被染色时间小于当前时间时,就可以返回这个结点了,否则进行路径压缩(进入否则,说明这个结点的最快被染色时间大于查询时间,而我们是倒着进行操作的,说明后继的查询时间都比当前的查询时间小,不管怎么样,这个结点都不会被染色了,无用,直接拿来压缩掉)

    #include<cstdio>  
    #include<iostream>  
    #define ll long long  
    using namespace std;  
      
    const int INF = 0x7f7f7f7f;  
    const int MAXN = 1e5 + 111;  
      
    int p[MAXN];  
    int qt[MAXN], qv[MAXN], mark[MAXN];  
    int t;  
      
    int find(int x) {  
        return mark[x] < t ? x : p[x] = find(p[x]); // 小于则说明在查询之前已经染过颜色  
    }  
      
    int main()  
    {  
        int n, q;  
        while (~scanf("%d%d", &n, &q) && (n | q)) {  
            for (int i = 2; i <= n; ++i) {  
                scanf("%d", p + i);  
                mark[i] = INF;  
            }  
      
            int cnt = 0, x;  
            char op[2];  
            for (int i = 1; i <= q; ++i) {  
                scanf("%s%d", op, &x);  
                if (op[0] == 'M') mark[x] = min(mark[x], i); // 记录最早染色时间  
                else {  
                    qt[cnt] = i;  
                    qv[cnt++] = x;  
                }  
            }  
      
            ll ans = 0;  
            while (cnt --) {  
                t = qt[cnt]; // 查询发生的时间  
                ans += find(qv[cnt]);  
            }  
            printf("%lld
    ", ans);  
        }  
        return 0;  
    }  
  • 相关阅读:
    JS代码判断IE不同版本
    极简技术类录--正则表达式
    Java读取系统Properties
    极简技术类录--maven
    极简技术类录--git
    JVM字节码增强
    如何避免死锁?
    有三个线程T1,T2,T3,怎么确保它们按顺序执行?
    编写两个线程,顺序输出自然顺序:1,2,3,4,...,99,100
    对文本单词进行技数,并倒序列出计数统计
  • 原文地址:https://www.cnblogs.com/demian/p/7384348.html
Copyright © 2020-2023  润新知