铁一中2018.10.29模拟赛t2(并查集)

题目:

题目描述

平面上有n个珠子排成一排, 每个珠子初始颜色为0,你要对他们进行m次染色,每次你选定l和r,然后把[l,r]之间的珠子染成编号c的颜色,每个珠子的最终颜色为它曾经染过的编号最大的颜色,请你写个程序统计每个珠子最终的颜色。

输入格式

第一行两个数n,m,表示珠子个数和染色的次数
接下来m行,每行三个数l,r,c如题意所示

输出格式

由于数据较大,为了减少输出所用的不必要的时间,请采取以下方法输出:
假如a[i]为第i个珠子的最终颜色

ans := 0;

for i := 1 to n do ans := (ans * 1200007 + a[i]) mod 999911659;

writeln(ans);

注意用int64保存相关变量,防止运算过程中越界

样例输入

3 2

1 2 1

2 2 2

样例输出

146411103

数据范围

30% n,m<=5000

50% n,m <= 10000

80% n,m <= 500000

100% n <= 1000000, m <= 2000000

时间限制

3s

题解:

本题非常简单,我们可以把染色按颜色大小排序,先处理大的,每个珠子只染一次。关键在下一次能够直接跳过已经染过的珠子,不然时间复杂度就超了,现在看一个经典的 O ( n ) O(n) O(n)并查集做法:

使每个珠子的祖先为在它(或它本身)前面的第一个需要处理的珠子,于是每次我们处理完一个珠子,直接把它与它前面的珠子合并即可。需要注意的是此题中珠子数较大,find函数最好用非递归形式。

代码:

#include 
#include 
#include 
using namespace std;
const int N=1e6+50;
const int M=2e6+50;
struct Qu{
	int l,r,c;
}qu[M];
int n,m;
int a[N],fa[N];

bool cmp(Qu a,Qu b){
	return a.c>b.c;
}

inline int find(int x) {
	int bx=x;
	while (bx!=fa[bx]) {
		bx=fa[bx];
	}
	while(x!=fa[x]){
		int ass=x;
		x=fa[x];
		fa[ass]=bx;
	}
	return bx;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&qu[i].l,&qu[i].r,&qu[i].c);
	sort(qu+1,qu+1+m,cmp);
	for(int i=1;i<=m;i++)
	{
		int li=qu[i].l,ri=qu[i].r,ci=qu[i].c;
		ri=find(ri);
		while(ri>=li){
			a[ri]=ci;
			fa[ri]=ri-1;
			ri=find(ri);
		}
	}
	long long ans=0;
	for(int i=1;i<=n;i++)
		ans=(ans*1200007ll+(long long)a[i])%999911659ll;
	cout<<ans<<endl;
	return 0;
}

你可能感兴趣的:(数据结构)