Codeforces Round #286 div.1 D 506D D. Mr. Kitayuta's Colorful Graph【并查集】

题目链接:http://codeforces.com/problemset/problem/506/D

题目大意:

给出n个顶点,m条边,每条边上有一个数字,代表某个颜色。不同数字代表不同的颜色。有很多个询问,每个询问问有多少条纯种颜色的路径使得某两个点联通。

分析:

这个题一看就想用并查集来搞,每种颜色用一个并查集处理。对于输入的每条边,我们只需要将这两个点在这条边的颜色对应的并查集中合并就好了。查询的时候,我们只需要检测这两个点在多少个颜色对应的并查集中是在统一集合中的,那么就有多少条纯种颜色的路径使得两个点联通了。

看起来好像很简单呢,但是我们注意到这个题的数据范围,不管是顶点,还是颜色,还是询问,还是边数,都是10^5的数量级的,那么这么一股脑的敲出来肯定是不行的。

首先,最大的问题就是,题目中有多少中颜色就得有多少个并查集,每个并查集也得有n的顶点的容量,在最大数据的情况下,这样的数组是万万开不下来的。。。那该怎么办?

这里我们可以先将所有输入的边存下来,按照颜色值排一下序,对每一种颜色集中处理,将这种颜色需要的信息提炼出来,在遇到下一种颜色的时候,上一个颜色的并查集就没有用,可以继续使用这个并查集的空间来存储。这样的话,我们的并查集在查询的时候就用不了了,只能离线将答案保存好。查询的时候o(1)输出。

离线将答案保存的方法,由于查询的是一对点,我们就只能用map建立pair到int的映射了。

好像这样就可以了呢!真的是这样吗?我们想想,在对每一种颜色集中处理过程中,需要找出查询中有的,并且在这一种颜色的并查集中属于同一集合的点对找出来。这是比较难的工作。做法是这样的,将这一颜色代表的图中的顶点存下来,然后两层for循环暴力遍历每个点对,查找满足条件的点对。这种做法在颜色比较多,每一种颜色中的点不多的时候是不会超时的,但是如果在每种颜色代表的图中含有的点比较多的话,这样的两层for循环就会超时了。。。无奈只好设置一个阀值,如果某种颜色中的点数小于这个阈值,那就两层for循环暴力扫。如果大于这个阈值,那就直接遍历所有询问,检测需要查询的所有点对即可。

于是。。。我用了一种极其丑陋的姿势过了这题。。T.T

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
#define N 100010

struct Info{
    int u,v,c;
    bool operator<(const Info o) const
    {
        return c<o.c;
    }
}info[N];
map<pair<int,int>,int> ans;
vector<pair<int,int> > uniQ;
struct query{
    pair<int,int> q;
}Q[N];
int par[N];
int n,m;
bool vervis[N];

void init(int* par,int n)
{
    for(int i=1;i<=n;i++)
    {
        par[i]=i;
    }
}
int find(int* par,int x)
{
    if(x==par[x])
        return x;
    return par[x]=find(par,par[x]);
}
void Union(int* par,int u,int v)
{
    u=find(par,u);
    v=find(par,v);
    if(u==v) return ;
    par[v]=u;
}

int main()
{
    #ifndef ONLINE_JUDGE
            //freopen("E:/in.txt","r",stdin);
            //freopen("E:/my.txt","w",stdout);
    #endif
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=0;i<m;i++)
        {
            int u,v,c;
            scanf("%d%d%d",&u,&v,&c);
            info[i].u=u,info[i].v=v,info[i].c=c;
        }
        sort(info,info+m);
        init(par,n);
        int qnum;
        scanf("%d",&qnum);
        for(int i=0;i<qnum;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            Q[i].q.first=min(u,v),Q[i].q.second=max(u,v);
            uniQ.push_back(Q[i].q);
            ans[Q[i].q]=0;
        }
        sort(uniQ.begin(),uniQ.end());
        uniQ.resize(unique(uniQ.begin(),uniQ.end())-uniQ.begin());
        vector<int> ver;
        for(int i=0;i<m;i++)
        {
            int u=info[i].u,v=info[i].v,c=info[i].c;
            Union(par,u,v);
            if(!vervis[u]) ver.push_back(u);
            if(!vervis[v]) ver.push_back(v);
            vervis[u]=1,vervis[v]=1;
            if(info[i+1].c!=info[i].c)
            {
                if(ver.size()*ver.size()>uniQ.size())
                {
                    for(int j=0;j<uniQ.size();j++)
                    {
                        int au=uniQ[j].first;
                        int av=uniQ[j].second;
                        if(find(par,au)==find(par,av))
                            ans[uniQ[j]]++;
                    }
                }
                else {
                    for(int j=0;j<ver.size();j++)
                    {
                        int au=ver[j];
                        for(int k=j+1;k<ver.size();k++)
                        {
                            int av=ver[k];
                            if(find(par,au)==find(par,av)&&ans.count(make_pair(min(au,av),max(au,av))))
                                ans[make_pair(min(au,av),max(au,av))]++;
                        }
                    }
                }
                if(i!=m-1){
                    for(int j=0;j<ver.size();j++)
                    {
                        par[ver[j]]=ver[j];
                        vervis[ver[j]]=0;
                    }
                    ver.clear();
                }
            }
        }
        for(int i=0;i<qnum;i++)
        {
            cout<<ans[Q[i].q]<<endl;
        }
    }
    return 0;
}

Codeforces Round #286 div.1 D 506D D. Mr. Kitayuta's Colorful Graph【并查集】

时间: 2024-10-19 20:18:08

Codeforces Round #286 div.1 D 506D D. Mr. Kitayuta's Colorful Graph【并查集】的相关文章

Codeforces 506D Mr. Kitayuta&#39;s Colorful Graph 并查集+水水的分类讨论+水水的离线预处理

首先读入所有的边与询问.将边按颜色分类. 按颜色进行并查集, 若此并查集内的点<= 100,则100*100/2的枚举是否联通. 若此并查集内的点  > 100,则将与这些点相关的所有询问查一遍. 那么时间复杂度为100*100/2*(M/100),或者为M/100*Q. 极限的时候两种方法都在一亿左右了,而且每次还需要在map里搞一搞,还要查询是否联通,不知道为啥没有超时.. #include <algorithm> #include <iostream> #incl

Codeforces Round #286 (Div. 2)B. Mr. Kitayuta&#39;s Colorful Graph(dfs,暴力)

数据规模小,所以就暴力枚举每一种颜色的边就行了. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm>

Codeforces Round #286 div.2 D 505D. Mr. Kitayuta&#39;s Technology【强连通分量,弱联通分量】

题目链接:http://codeforces.com/contest/505/problem/D 题目大意: 在一个图中,有n个顶点,给出m对数字(u,v)表示顶点u和顶点v必须直接或者间接相连,让你构造一个这样的图,输出最少需要多少条边. 分析: 毫无疑问,n个顶点的话,我们最多可以用n条边,使得n个顶点构成一个环,满足所有的情况(任意两点都是联通的),但是这并不一定是最少的边. 于是我们还需要找一个方法确定最少需要多少条边. 首先我们利用题目给出的点对建图,得到图G.对于G中的弱联通分量来说

Codeforces Round #286 (Div. 2)A. Mr. Kitayuta&#39;s Gift(暴力,string的应用)

由于字符串的长度很短,所以就暴力枚举每一个空每一个字母,出现行的就输出.这么简单的思路我居然没想到,临场想了很多,以为有什么技巧,越想越迷...是思维方式有问题,遇到问题先分析最简单粗暴的办法,然后一步一步的优化,不能盲目的想. 这道题要AC的快需要熟悉string的各种用法.这里做个简单总结:C++中string的常见用法. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstrin

Codeforces Round #286 (Div. 2) B. Mr. Kitayuta&#39;s Colorful Graph +foyd算法的应用

B. Mr. Kitayuta's Colorful Graph time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Mr. Kitayuta has just bought an undirected graph consisting of n vertices and m edges. The vertices of the g

水题 Codeforces Round #286 (Div. 2) A Mr. Kitayuta&#39;s Gift

题目传送门 1 /* 2 水题:vector容器实现插入操作,暴力进行判断是否为回文串 3 */ 4 #include <cstdio> 5 #include <iostream> 6 #include <algorithm> 7 #include <cstring> 8 #include <string> 9 #include <vector> 10 using namespace std; 11 12 const int MAXN

DFS/并查集 Codeforces Round #286 (Div. 2) B - Mr. Kitayuta&#39;s Colorful Graph

题目传送门 1 /* 2 题意:两点之间有不同颜色的线连通,问两点间单一颜色连通的路径有几条 3 DFS:暴力每个颜色,以u走到v为结束标志,累加条数 4 注意:无向图 5 */ 6 #include <cstdio> 7 #include <iostream> 8 #include <algorithm> 9 #include <cstring> 10 #include <string> 11 #include <vector> 1

Codeforces Round #286 (Div. 1) D. Mr. Kitayuta&#39;s Colorful Graph

D - Mr. Kitayuta's Colorful Graph 思路:我是暴力搞过去没有将答案离线,感觉将答案的离线的方法很巧妙.. 对于一个不大于sqrt(n) 的块,我们n^2暴力枚举, 对于大于sqrt(n)的块,我们暴力枚举答案. 这样就能做到严格sqrt(n) * n #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #defin

B. Mr. Kitayuta&#39;s Colorful Graph (CF #286 (Div. 2) 并查集)

B. Mr. Kitayuta's Colorful Graph time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Mr. Kitayuta has just bought an undirected graph consisting of n vertices and m edges. The vertices of the g