首页 > 编程语言 >洛谷题单指南-集合-P1955 [NOI2015] 程序自动分析

洛谷题单指南-集合-P1955 [NOI2015] 程序自动分析

时间:2024-03-26 15:11:24浏览次数:38  
标签:P1955 相等 end 10 int 洛谷题 back NOI2015 push

原题链接:https://www.luogu.com.cn/problem/P1955

题意解读:要判断约数条件是否可以同时满足,主要是要判断不相等的情况。

解题思路:

对于相等的条件,直接进行集合合并即可;

对于不相等的条件,判断两者是否属于同一个集合,如果形成矛盾,则条件不能成立。

由于i,j的范围至10^9,定义并查集如果直接p[N],N=1e9+5,则会导致内存溢出

而n最多不过10^5,因此,可以对i,j进行离散化处理:

对出现的所有i,j进行排序、去重,用二分来找到i,j的下标代替其本身,这样,数据范围可以缩小到2 * 10^5规模。

所谓离散化,就是将一个范围比较大的数据集映射到一个范围较小的数据集的过程,这里代码处理如下:

首先,读入所有出现过的i,j,将其保存如vector<int> a

while(n--)
{
    cin >> i >> j >> e;
    a.push_back(i); 
    a.push_back(j);
}

再对a进行排序

sort(a.begin(), a.end());

再对a进行去重,有两种方法可以去重

1、STL去重法,借助于erase和unique函数,适合对STL有良好记忆的朋友

a.erase(unique(a.begin(), a.end()), a.end());

2、手动去重,将去重后的数据存入vector<int> b,适合不想记忆STL的朋友

for(int i = 0; i < a.size(); i++)
{
    if(i == 0 || a[i] != a[i - 1]) b.push_back(a[i]);
}

由于i,j的范围是1~10^9,但是一共只有n=10^5对,也就是最多有2*10^5个数,去重之后,b的size最多在2*10^5

因此,要将一个10^9范围的数映射到2*10^5范围,只需要用二分在b中查找数的下标即可,一个数对应唯一一个下标,对原数的处理都可以转为对下标的处理,这样在定义并查集的时候只需要定一个一个2*10^5长度的数组即可,就不会导致内存溢出问题,这就是离散化最大的作用。

下面给出完整代码。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;

struct node
{
    int i, j, e;
};

int p[N]; 
vector<int> a, b; //a保存所有i,j,用来做离散化处理, b是a排序、去重之后的结果
vector<node> c, d; //c保存所有相等条件,d保存所有不相等的条件

int t, n, i, j, e;

//在b中找到x所在的位置
int bs(int x)
{
    int l = 0, r = b.size() - 1, ans = -1;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(b[mid] >= x) 
        {
            ans = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
    return ans + 1; //使得下标从1开始
}

int find(int x)
{
    if(p[x] == x) return x;
    return p[x] = find(p[x]);
}

void merge(int x, int y)
{
    p[find(x)] = find(y);
}

int main()
{
    cin >> t;
    while(t--)
    {
        cin >> n;
        a.clear();
        b.clear();
        c.clear();
        d.clear();
        while(n--)
        {
            cin >> i >> j >> e;
            //将所有出现过的i,j存入a中
            a.push_back(i); 
            a.push_back(j);
            if(e == 1) c.push_back({i, j, e}); //将所有相等的条件存入c中
            if(e == 0) d.push_back({i, j, e}); //将所有不相等的条件存入d中
        }
        
        //对a排序
        sort(a.begin(), a.end());
        //对a去重,得到b
        //也可以直接a.erase(unique(a.begin(), a.end()), a.end());
        for(int i = 0; i < a.size(); i++)
        {
            if(i == 0 || a[i] != a[i - 1]) b.push_back(a[i]);
        }

        //初始化并查集
        for(int i = 1; i <= b.size(); i++) p[i] = i;
        //把所有相等的条件进行集合合并
        for(int i = 0; i < c.size(); i++)
        {
            int ni = bs(c[i].i), nj = bs(c[i].j);
            merge(ni, nj); 
        }
        bool yes = true;
        //判断不相等的条件是否有矛盾
        for(int i = 0; i < d.size(); i++)
        {
            int ni = bs(d[i].i), nj = bs(d[i].j);
            if(find(ni) == find(nj))
            {
                yes = false;
                break;
            }
        }
        if(yes) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

 

标签:P1955,相等,end,10,int,洛谷题,back,NOI2015,push
From: https://www.cnblogs.com/jcwy/p/18096711

相关文章

  • 洛谷题单指南-集合-P1892 [BOI2003] 团伙
    原题链接:https://www.luogu.com.cn/problem/P1892题意解读:此题与关押罪犯问题非常像,本质上就是要合并所有的朋友。解题思路:首先,初始化并查集;对于每一对人的关系,如果是朋友,直接进行合并;如果是敌人,先查看双方之前是否有记录其他敌人,如果有,则将一方与另一方的敌人进行合并,如果没......
  • 洛谷题单指南-集合-P1621 集合
    原题链接:https://www.luogu.com.cn/problem/P1621题意解读:a~b之间的数,把有大于等于p的公共质因数的数进行合并作为一个集合,求一共有多少个集合。解题思路:要进行集合合并、统计集合数,可以使用并查集,有两种做法:1、暴力法80%的数据在1000范围内,因此通过双重循环枚举,判断两个数的......
  • 洛谷题单算法1-6二分查找与二分答案
    代码仅供参考,不足之处望理解。P2249【深基13.例1】查找#include<iostream>usingnamespacestd;constintN=1e6+5;intn,m,a[N];intmain(){ios::sync_with_stdio(false);//输入cin>>n>>m;for(inti=1;i<=n;i++)cin>>a[i];for(inti=1......
  • C语言:洛谷题目分享(4)小书童--凯撒密码和笨小猴
    目录1.前言2.俩道题目1.小书童--凯撒密码1.题目背景2.题目描述3.输入格式4.输出格式5.题解2.笨小猴1.题目描述2.输入格式3.输出格式4.题解3.小结1.前言哈喽大家好啊,今天我继续为大家分享洛谷题单的俩道题目,请大家多多支持喔~2.俩道题目1.小书童--凯撒密码......
  • 洛谷题单指南-集合-P1525 [NOIP2010 提高组] 关押罪犯
    原题链接:https://www.luogu.com.cn/problem/P1525题意解读:有很多罪犯,要关到两座监狱,有一些罪犯之间有仇,并且可以量化出仇恨值,如果关在一起就会冲突,造成的影响就是仇恨值,要使得造成的影响最小,如果可以完全不起冲突,输出0。解题思路:首先,要让冲突影响最小化,显然应该把仇恨大的罪犯......
  • 洛谷题单指南-集合-P1102 A-B 数对
    原题链接:https://www.luogu.com.cn/problem/P1102题意解读:前文https://www.cnblogs.com/jcwy/p/18043197介绍了二分和双指针的做法,本文介绍hash的做法。解题思路:定义map<int,int>h,保存每个数+c出现的个数同样,先将所有数由小到大哦排序遍历每一个数x,答案累加ans+=h[x]然......
  • 洛谷题单指南-集合-P5266 【深基17.例6】学籍管理
    原题链接:https://www.luogu.com.cn/problem/P5266题意解读:本题考察map的应用。解题思路:直接使用map即可解题。100分代码:#include<bits/stdc++.h>usingnamespacestd;map<string,int>h;stringname;intn,op,score;intmain(){cin>>n;while(n--)......
  • 洛谷题单指南-集合-P5250 【深基17.例5】木材仓库
    原题链接:https://www.luogu.com.cn/problem/P5250题意解读:根据题目要求,需要一种数据结构,支持去重、排序、logN的查找,set是最合适的。解题思路:先回顾一下set的关键操作:设set<int>s;1、添加:s.insert(x)2、查询个数:s.count(x)3、查找第一个>=x的元素,返回迭代器:set<int>::iter......
  • 洛谷题单指南-集合-P3370 【模板】字符串哈希
    原题链接:https://www.luogu.com.cn/problem/P3370题意解读:本题要求理解哈希的原理,自行建立哈希表解题,如果直接使用map,就不推荐。解题思路:先介绍哈希的原理1、什么是哈希?什么是哈希表?先从一个问题出发:给定不超过105个整数(取值1~109),要统计不重复整数的数量。首先,如果取值范围......
  • 洛谷题单指南-集合-P1536 村村通
    原题链接:https://www.luogu.com.cn/problem/P1536题意解读:城镇之间现有的道路关系可以将城镇划分的若干集合,每个集合内的城镇是互通的,要计算最少增加多少条道路,使得每个集合都相通。解题思路:利用并查集,统计一共出现多少个集合,即p[i]=i的数量,最少的道路数即集合数-1,即可把所......