题解 | #拆路#

拆路

https://ac.nowcoder.com/acm/problem/235745

思路:

1、维护每个集合的最大繁荣值,只需要将最大繁荣值的节点设置成根节点,每次查找x所在集合的最大繁荣值时只需要找到x的根节点,根节点的繁荣值即为最大繁荣值。每次合并两个集合时,让较小繁荣值的根节点指向较大繁荣值的根节点。

2、如果按照普通方法先进行m次建边操作,再遍历q次询问或删边操作,会发现并查集难以维护删边操作。如何避免进行删边操作呢?

3、先用mp存储下这m个建边操作,再用op存储这q个询问或删边操作,对于每个删边a-b的操作,我们将mp中存储的这条边a-b删掉。这样mp中剩余的边都是不再需要进行删边的操作。所以可以直接遍历剩余的mp中的所有边进行建边操作。然后从后往前遍历这op中存储的q个操作,每次询问操作Qa我们将答案存入res。每次删边操作Dab我们进行建边操作。遍历结束后倒序输出res中存储的答案即可。

4、举例模拟:假如有两个点a,b相连,a的繁荣值为1,b的繁荣值为10。3个操作分别是Qa,Dab,Qa。则正确答案应该输出10,再输出1。模拟一遍。由于有Dab操作所以我们不进行建边a-b操作。从后往前遍历这3个操作,先将Qa得到的答案1存入res。Dab进行建边a-b操作,再进行Qa得到答案10存入res。此时res中存储的答案为res={1,10}。倒序输出res中的答案与正确答案相符

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+6;
int p[N],impact[N];//p[N]存储每个节点的父节点,impact[N]存储每个节点的繁荣值
set<pair<int,int>>mp;//mp存储需要建的m条边
vector<int>res;//存要输出的答案,因为是从后往前遍历所有op,所以先把所有要输出的答案存入res,最后倒序输出
struct OP//op[N]保存q个询问或删边操作
{
    char c;
    int a,b;
}op[N];
int n,m,q;
 
int Find(int x)//返回x节点的根节点
{
    if(p[x]!=x) p[x]=Find(p[x]);
    return p[x];
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;++i) 
    {
        cin>>impact[i];//输入繁荣值
        p[i]=i;//初始化每个点的父节点
    }
    for(int i=0;i<m;++i)//用mp存储所有要建的边
    {
        int x,y;
        cin>>x>>y;
        mp.insert({x,y});
    }
    
    cin>>q;
    for(int i=0;i<q;i++)//输入q个操作并用op[N]保存这些操作
    {
        cin>>op[i].c>>op[i].a;
        if(op[i].c=='D')//对于每个删边a-b的操作,我们将mp中存储的这条边a-b删掉,使得循环结束后mp中剩余的边都是不再需要进行删边的操作的边
        {
            cin>>op[i].b;
            mp.erase({op[i].a,op[i].b});//删掉地图里的a-b的边
            mp.erase({op[i].b,op[i].a});//a-b和b-a是同一条边,可能mp中只存了a-b或者只存了b-a。
        }
    }
    for(auto i:mp)//建图,mp中存储的边都是不会被删掉的边
    {
        int x=i.first,y=i.second;
        int px=Find(x),py=Find(y);//提取x,y的根节点
        if(impact[px]>impact[py]) p[py]=px;//繁荣值小的指向繁荣值大的
        else p[px]=py;
    }
    
    for(int i=q-1;i>=0;i--)//从后往前遍历这m个操作
    {
        if(op[i].c=='Q') res.push_back(impact[Find(op[i].a)]);//每次询问操作用res保存根节点的繁荣值
        else//每次删边操作时进行建边
        {
            int x=op[i].a,y=op[i].b;
            int px=Find(x),py=Find(y);//提取x,y的根节点
            if(impact[px]>impact[py]) p[py]=px;//繁荣值小的指向繁荣值大的
            else p[px]=py;
        }
    }
    for(int i=res.size()-1;i>=0;i--) 
        cout<<res[i]<<endl;//倒序输出res里的元素
}
全部评论

相关推荐

3 收藏 评论
分享
牛客网
牛客企业服务