题目:
题目描述
平面上有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 <iostream>
#include <stdio.h>
#include <algorithm>
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;
}