我们爱序列 (sequence)

我们爱序列 (sequence)

AngryBacon 非常喜欢序列,与序列有关的一切都喜欢。
AngryBacon 面前摆着一个长度为 N 的序列,每个元素为不超过 M 的正整数。
AngryBacon 会使用 Q 次魔法,每次魔法的内容为一对不超过 M 的正整数 a,b,表示将序列中所有
为 a 的数改写为 b。
AngryBacon 想知道在最后他心爱的序列变成了什么样。
输入格式
第一行,包含三个整数 N,M,Q,意义如上所述。
第二行,包含 N 个整数 A1,A2,……,AN ,表示初始序列。
接下来的 Q 行,每行两个整数 a,b,意义如上所述。
输出格式
输出一行,包含 N 个整数,表示最后序列的形态。
输入输出样例
输入
5 5 3
1 2 3 4 5
3 1
4 3
1 5

输出
5 2 5 3 5
数据范围
• 对于 20% 的数据, 1 ≤ N,M,Q ≤ 1,000。
• 对于另外 40% 的数据, 1 ≤ N,Q ≤ 100,000, 1 ≤ M ≤ 20。
• 对于 100% 的数据, 1 ≤ N,M,Q ≤ 1000,000, 1 ≤ a,b,Ai ≤ M。
时间限制
2 秒


题解

这题是本次考试中最简单的小题了。第一眼看完的想法就是并查集,但是我们发现并查集是有问题的(样例就是反例)。假如我们把 a 变成 b,再把 c 变成 a,并查集的代码会认为我们的 c 也变成了 b(a、b、c表示所有值为a、b、c的点)。

对于这种情况,我们可以用一个数组 h 标记值为 i 的所有元素的点的祖先,即h[A[i]] = getfa(i) 其中 i 是所有值为 A[i] 的节点的祖先节点。当我们把 a 变成 b 时,如果 h[b] 不为 0,那么我们就把 h[a] 和 h[b] 交换,否则,就把 h[a]设为 0,再把 a 的祖先设为 b。这样就可以快速完成操作了,可是问题是我们不知道答案,所以要再开一个 s 数组,再过程中修正祖先节点的值,最后输出的值就是每个点的祖先节点的值。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1000005;
int n,m,q,a,b,x,h[maxn],s[maxn],fa[maxn],tot;
int read()
{
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
int get(int x){return fa[x]==x? x:fa[x]=get(fa[x]);}
void dfs(int x)
{
    if (x) dfs(x/10);else return;
    putchar((char)(x%10+'0'));
}
int main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    n=read();m=read();q=read();
    for (int i=1;i<=n;i++) fa[i]=i;
    for (int i=1;i<=n;i++)
    {
        x=read();
        if (!h[x]) h[x]=i,s[i]=x;
        else fa[i]=get(h[x]);
    }
    for (int j=1;j<=q;j++)
    {
        a=read(),b=read();
        int &ha=h[a],&hb=h[b];
        if (ha)
        {
            int t=ha;ha=0;
            if (hb) fa[get(t)]=get(hb);
            else hb=t,s[t]=b;
        }
    }
    for (int i=1;i<=n;i++)
    {
        int x=s[get(i)];dfs(x);
        if (i!=n) putchar(' ');
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值