Aizu2170/AOJ2170

这题我看到最好的做法就是不带路径压缩的并查集,简单明了。其实题目很类似于平时的并查集模板题,但是有一个不同的地方就是会不停地添加标记,相当于改变某一部分的祖先,那么如果按照平时的做法去路径压缩的话就会出现问题,因此我们只要把路径压缩那一块去掉就好了。
题目中当mark一个点时,我们就用fa[x]=x去更新某个点,使它作为一个并查集的根节点,然后如果要查询离x最近的mark点,那么我们就逐渐网上找,找到第一个fa[x]=x的点,然后返回它的值,注意,这过程中我们不能进行路径压缩。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int par[100005];
int find(int x)
{
    return x==par[x]?x:find(par[x]);//带路径压缩后面就应该是par[x]=find(par[x])
}
int main()
{
    int n,q,i,j;
    while(cin>>n>>q&&(n+q)){
        for(i=1;i<n;i++)
            scanf("%d",&par[i+1]);//注意本题中par[i]并不需要初始化!
        par[1]=1;getchar();char c;long long ans=0;//可能爆int
        for(i=1;i<=q;i++){
            c=getchar();scanf("%d",&j);getchar();
            if(c=='M')par[j]=j;
            else{
                ans+=(long long)find(j);
            }
        }
        cout<<ans<<endl;
    }

    return 0;
}
/*
 ━━━━━┒
 ┓┏┓┏┓┃μ'sic foever!!
 ┛┗┛┗┛┃\○/
 ┓┏┓┏┓┃ /
 ┛┗┛┗┛┃ノ)
 ┓┏┓┏┓┃
 ┛┗┛┗┛┃
 ┓┏┓┏┓┃
 ┛┗┛┗┛┃
 ┓┏┓┏┓┃
 ┛┗┛┗┛┃
 ┓┏┓┏┓┃
 ┃┃┃┃┃┃
 ┻┻┻┻┻┻
 */

此外还有一种做法就是不用并查集,直接递归解决问题。直接记录了每一个节点的父亲节点,每一次搜索就计算到他的染色父亲结点为止。二元组pair的第一个值记录当前点的祖先,第二个值则代表该点是否被染色。

#include <iostream>
#include<stdio.h>
#define MAX_N 100005
using namespace std;
typedef long long ll;
typedef pair<int ,bool> p;
p fa[MAX_N];
int main(){
    int n,q;
    fa[1].first = 1;
    fa[1].second = true;
    while(~scanf("%d%d",&n,&q)&&n>0){
        ll ans = 0;
        for(int i = 2;i <= n;i++){
            scanf("%d",&fa[i].first);
            fa[i].second = false;
        }
        getchar();
        for(int i = 0;i<q;i++){
            char ch;int a;
            scanf("%c%d",&ch,&a);
            getchar();
            if(ch =='Q'){
                while(fa[a].second==false){
                    a = fa[a].first;
                }
                ans += a;
            }
            else{
                fa[a].second = true;
            }

        }
        printf("%lld\n",ans);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值