2019ICPC(徐州) - so easy(并查集+离散化)

题目链接:点击查看

题目大意:给出一个1~n的序列,然后给出m个操作,每个操作分为下列两种情况:

  1. 1 x:让数字x不可用
  2. 2 x:查询包括x在内的右侧的第一个可用数字

题目分析:因为n给到了1e9,而查询只有1e6,所以我们必须将数据离散化,我最初的思路是先将1e6个查询记录下来,将操作1使用过的数字放到一个有序数列中,离线处理,可以倒着一步步模拟,每次遇到操作1就将其删除(即加入回原数组中),然后二分查找第一个大于等于它本身的数,我让队友模拟的,最后果然这个题目卡了stl的时间,TLE了,然后我就想用vector模拟链表写一下这个题,经过队友的提醒,发现了这就是一个离散化后的并查集,但我不太会写,就先用vector正向模拟的这个题目,最后还是以TLE告终,临比赛结束前半个小时终于有了最终的思路,就是在离散化的时候,将涉及到的x和x+1同时加入到并查集中,这样正向遍历一遍询问,每次遇到删除就将当前节点的父节点改为下个节点的父节点,遇到询问就直接输出该节点的父节点即可

不过还是需要注意一下离散化后的id和并查集的对应关系,写那一部分的时候一定要细心想一下,不能对应错

还有个细节需要注意一下,因为每次push进去的是点x和点x+1,所以最坏情况会有2e6个点,所以数组要开2e6,开1e6会RE

题解是说用map并查集维护一条链表,不过不能用普通的map,会超时,要用unordered_map,据说是O1的查询

补充一下map和unordered_map的区别吧:

map:

map内部实现了一个红黑树,该结构具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素,因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行这样的操作,故红黑树的效率决定了map的效率。 
unordered_map:

unordered_map内部实现了一个哈希表,因此其元素的排列顺序是杂乱的,无序的

其他方法都是一样的用法

蒟蒻的代码:(又臭又长但条理还挺清晰的-.-)

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream> 
using namespace std;

typedef long long LL;

const int inf=0x3f3f3f3f;

const int N=2e6+100;

vector<int>v;

int fa[N];

int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}

struct Node
{
	int op,x;
}q[N];

int getid(int x)
{
	return lower_bound(v.begin(),v.end(),x)-v.begin();
}

int main()
{
//	freopen("input.txt","r",stdin);
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		v.clear();
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d",&q[i].op,&q[i].x);
			v.push_back(q[i].x);
			v.push_back(q[i].x+1);
		}
		v.push_back(n);
		sort(v.begin(),v.end());//离散化+去重
		v.erase(unique(v.begin(),v.end()),v.end());
		for(int i=0;i<v.size();i++)
			fa[i]=i;
		for(int i=1;i<=m;i++)
		{
			int op=q[i].op;
			int x=q[i].x;
			int id=getid(x);
			if(op==1)
			{
				fa[id]=find(id+1);
			}
			else
			{
				printf("%d\n",v[find(id)]);
			}
		}
	}

	
	
	
	
	
	
	
	

	return 0;
}

题解的代码:顺便偷学了一波unordered_map

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5 + 100;
unordered_map<int, int> fa;

int findfa(int x) {
    if (!fa.count(x)) return x;
    return fa[x] = findfa(fa[x]);
}


int main() {
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    int n, q;
    scanf("%d %d", &n, &q);
    int op, x;
    while (q--) {
        scanf("%d %d", &op, &x);
        if (op == 1) {
            fa[x] = findfa(x + 1);
        } else {
            int ans = findfa(x);
            if (ans > n) ans = -1;
            printf("%d\n", ans);
        }
    }
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frozen_Guardian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值