bzoj 3893: [Usaco2014 Dec]Cow Jog 并查集+单调队列

来源:互联网 发布:中文翻译软件哪个好 编辑:程序博客网 时间:2024/06/05 08:47

题意

在一条无限长的跑道上有N头牛,每头牛有自己的初始位置及奔跑的速度。牛之间不能互相穿透。当一只牛追上另一只牛时,它不得不慢下来,成为一个群体。求T分钟后一共有几个群体。
n<=100000

分析

我们把每头牛跑过的区间求出来。显然若两头牛会合并当且仅当它们的区间满足包含关系。
那么我们就可以把区间按左端点排序后从前往后扫,然后维护一个右端点单调递增的单调队列。
每碰到一个区间,就把单调队列里面所有右端点比它大的区间与它合并即可。
复杂度O(nlogn)

貌似还有更简洁的O(n)做法。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=100005;int n,t,f[N],q[N];pair<LL,LL> a[N];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int find(int x){    if (f[x]==x) return x;    else return f[x]=find(f[x]);}int main(){    n=read();t=read();    for (int i=1;i<=n;i++)    {        int x=read(),y=read();        a[i]=make_pair((LL)x,(LL)x+(LL)t*y);        f[i]=i;    }    sort(a+1,a+n+1);    int top=0;    for (int i=1;i<=n;i++)    {        LL mx=a[i].second;        while (top&&a[q[top]].second>=a[i].second)        {            int x=find(q[top]),y=find(i);            if (x!=y) f[x]=y;            top--;        }        q[++top]=i;    }    int ans=0;    for (int i=1;i<=n;i++) if (f[i]==i) ans++;    printf("%d",ans);    return 0;}
原创粉丝点击