2017.10.31 T3 2025
样例数据
输入
4
0 5
3 8
5 6
4 7
输出
3
分析:如果是纯粹暴力,考虑到内存,只能AC20%,如果能离散化一下,就可以AC40%,如果用线段树操作,就可以AC70%(写的好的可以AC貌似)。但是正解竟然是并查集,学到了……离散化后(注意代码中的处理方式,直接离散化有bug)我们把颜色从最后往前加(一如既往的套路),用并查集将它们串起来,记录连起来的部分右侧第一格空白(相当于fa),这样就是O(NlogN)做一遍就完了(注意常数)。
代码
感觉我代码能力太弱了,改这道题花了好久orz
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;
int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}
const int N=4e6+100;
struct node{
int l,r;
}a[N/4];
int n,cnt,b[N],ans,jump[N],pos;
bool colr[N/4],visit[N];
inline void lsh()
{
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
int p=cnt;
for(int i=2;i<=cnt;++i)
if(b[i]!=b[i-1]+1)
b[++p]=b[i-1]+1;//如果两个相邻数差值大于1,有可能是两种颜色中间穿插了另一种颜色的情况
//(比如一条黄色1—5,后来又涂了红色1-2,绿色3-5,这里能看到三种颜色)
//离散化后这两个数就连在一起了,就把中间的颜色给覆盖了,所以必须强行加一个数在中间充当白纸
sort(b+1,b+p+1);
for(int i=1;i<=n;++i)
{
a[i].l=lower_bound(b+1,b+p+1,a[i].l)-b;
a[i].r=lower_bound(b+1,b+p+1,a[i].r)-b;
}
}
inline int find(int x)
{
if(visit[x]==false) return x;
return jump[x]=find(jump[x]);
}
int main()
{
freopen("ribbon.in","r",stdin);
freopen("ribbon.out","w",stdout);
n=getint();
for(int i=0;i<n;++i)
{
a[n-i].l=getint()+1,a[n-i].r=getint();
b[++cnt]=a[n-i].l,b[++cnt]=a[n-i].r;//离散化的数组
}
lsh();//离散化
int x,y;
for(int i=1;i<=n;++i)
{
x=a[i].l,y=a[i].r;
pos=find(y+1);//找到最右端在哪里
while(x<=y)
{
if(visit[x]==true) x=find(x);//如果这个地方已经涂过色,就跳,一直到第一格空白格
else
{
if(colr[i]==false)//涂上这种颜色就更新答案,打个标记免得继续涂还更新答案
ans++,colr[i]=true;
visit[x]=true;//这个点涂过了
jump[x]=pos;//给它跳的fa就是刚刚找到的最右空白格
x++;
}
}
}
cout<<ans<<'\n';
return 0;
}
本题结。