zoukankan      html  css  js  c++  java
  • Codeforces 1166 F. Vicky's Delivery Service 并查集+set

    题意:有n个点,m条边,边有c种颜色,q次操作。

    每个边都有一种颜色。

    然后操作有两种,一种是再加一条边,另一种是查询能否从x达到y。

    移动的限制是,连着走两步必须是同一种颜色,如果走奇数步,最后一步可以是任意颜色。

    例子:1-2-3-4-5-6。

    这个题颜色种类很多,我是用map<int,vector<int>>来存边。

    我们首先可以想到 对于点x同种颜色连着的点都是可以相互移动的,所以我们可以用这种方法将它们用并查集合并,我们也可以直接map<int,int>来存边,因为一个vector里的点是等价的。

    但是这样有一个问题,走偶数步可以走通的已经被我们合并可以直接查询了,那么最后一步能走到的怎么办呢?

    我们可以对每个联通集合存一个set,里面放集合中能一步走到的点。我们之后要合并集合,这个set自然也要合并,本来是想着用可并堆,但是其实用启发式合并也可以了。

    以下为代码:

    #include<bits/stdc++.h>
    using namespace std;
    int i,i0,n,m,c,q,pre[100005];
    map<int,vector<int>>mp[100005];
    set<int>dic[100005];
    int fin(int x){return (pre[x]==x)?x:pre[x]=fin(pre[x]);}
    void uni(int x,int y)
    {
        if(fin(x)!=fin(y))
        {
            if(dic[fin(x)].size()<dic[fin(y)].size())swap(x,y);
            for(auto i:dic[fin(y)])dic[fin(x)].insert(i),pre[fin(y)]=fin(x);
        }
    }
    void add()
    {
        int x,y,col;
        scanf("%d %d %d",&x,&y,&col);
        dic[fin(x)].insert(y),dic[fin(y)].insert(x);
        mp[x][col].push_back(y),uni(y,mp[x][col][0]);
        mp[y][col].push_back(x),uni(x,mp[y][col][0]);
    }
    int main()
    {
        scanf("%d %d %d %d",&n,&m,&c,&q);
        for(i=1;i<=n;i++)pre[i]=i;
        while(m--)add();
        while(q--)
        {
            char op;
            scanf(" %c",&op);
            if(op=='?')
            {
                int x,y;
                scanf("%d %d",&x,&y);
                printf("%s
    ",(fin(x)==fin(y)||dic[fin(x)].count(y))?"Yes":"No");
            }
            else add();
        }
        return 0;
    }
    
  • 相关阅读:
    oracle笔记
    随笔
    EclipsePDT PHP的开发环境配置
    winXP的系统如何避免他人在不需要密码的情况进入安全模式
    WINDOWS图片和传真查看器找不到
    Oracle常用语句大全
    jdbc连接oracle
    jdk与jre的区别
    mysql手工注入.md
    sql手工注入.md
  • 原文地址:https://www.cnblogs.com/megalovania/p/10896862.html
Copyright © 2011-2022 走看看