zoukankan      html  css  js  c++  java
  • Marked Ancestor [AOJ2170] [并查集]

    题意:
    有一个树,有些节点染色,每次有两种操作,第一,统计该节点到离它最近的染色父亲结点的的号码(Q),第二,为某一个节点染色(M),求第一种操作和。

    输入:

    输入由多个数据集组成。每个数据集都有以下格式:
    输入的第一行包含两个整数N和Q,分别表示树T中的节点数和操作数。这些数字满足以下条件:1≤N≤100000和1≤Q≤100000。
    下面的N-1行,每行包含一个整数pi(i = 2,...,N),它表示第i个节点的父节点的编号。
    接下来的Q行按顺序包含操作。每个操作都格式化为“M v”或“Q v”,其中v是节点的编号。

    样例:

    6 3

    1

    1

    2

    3 3

    Q 5

    M 3

    Q 5
    0 0

    样例输出:

    4

    分析:

    这道题乍一看是一道在树上玩的图论/数据结构题?

    但是我想半天都没想到有什么好一点的办法去做这道题。

    根据作业专题:并查集,我们来思考如何靠近并查集。

    显然并查集的功能是“并”,而这个题的要求显然是“拆”。

    我们如果倒过来看,拆就变成并了,而很多拆的题目就是反过来处理使用并查集的。

    那我们就把所有询问记录下来,并记录每个点被标记的最早时间。

    那我们在查询父节点的时候,条件便是 当前点被标记的时间早于查询时间 ? 该点 :递归父节点(路径压缩)

    我们是否担心路径压缩会出错?

    不会,因为我们倒序后,压缩的是已经晚于查询节点的时间的,而我们的查询时间是不断向前走的。

    代码:

     1 #include<set>
     2 #include<map>
     3 #include<queue>
     4 #include<stack>
     5 #include<cmath>
     6 #include<cstdio>
     7 #include<cstring>
     8 #include<iostream>
     9 #include<algorithm>
    10 #define RG register ll
    11 #define rep(i,a,b)    for(RG i=a;i<=b;++i)
    12 #define per(i,a,b)    for(RG i=a;i>=b;--i)
    13 #define ll long long
    14 #define inf (1<<29)
    15 #define maxn 100005
    16 using namespace std;
    17 ll n,T,x,cnt,tim,ans;
    18 ll fa[maxn],tag[maxn],qa[maxn],qb[maxn];
    19 inline ll read()
    20 {
    21     ll x=0,f=1;char c=getchar();
    22     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    23     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    24     return x*f;
    25 }
    26 
    27 ll find(ll x)
    28 {
    29     return tag[x]<tim?x:fa[x]=find(fa[x]);
    30 }
    31 
    32 int main()
    33 {
    34     while(1)
    35     {
    36         n=read(),T=read();
    37         if(n==0&&T==0)    return 0;
    38         ans=cnt=0;
    39         rep(i,2,n)    fa[i]=read(),tag[i]=i+T;
    40         char s[5];
    41         rep(i,1,T)
    42         {
    43             scanf("%s",s);x=read();
    44             if(s[0]=='M')
    45                 tag[x]=min(tag[x],i);
    46             else
    47                 qa[++cnt]=x,qb[cnt]=i;
    48         }
    49         per(i,cnt,1)
    50         {
    51             tim=qb[i];
    52             ans+=find(qa[i]);
    53         }
    54         cout<<ans<<endl;
    55     }
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    DB数据导出工具分享
    使用批处理脚本愉快的清理缓存
    git常用命令记录
    使用bat脚本部署hexo到coding和github
    初次尝试Linux并记录一二
    js实用方法记录-指不定哪天就会用到的js方法
    js实用方法记录-简单cookie操作
    js实用方法记录-js动态加载css、js脚本文件
    使用node自动生成html并调用cmd命令提交代码到仓库
    express使用记录
  • 原文地址:https://www.cnblogs.com/ibilllee/p/9226440.html
Copyright © 2011-2022 走看看