题意
《飞扬的小鸟》是一款风靡的小游戏。在游戏中,小鸟一开始位于(0,0)处,它的目标是飞到横坐标为X的某个位置上。每一秒,你可以选择点击屏幕,那么小鸟会从(x,y)飞到(x+1,y+1),或者不点击,那么小鸟会飞到(x+1,y-1)。在游戏中还有n个障碍物,用三元组(x[i],a[i],b[i])描述,表示在直线x=x[i]上,y<=a[i]或者y>=b[i]的部分都是障碍物,碰到或者擦边都算游戏失败。请求出小鸟从(0,0)飞到目的地最少需要点击多少次屏幕。
0<=n<=500000
分析
考虑从后往前模拟,对于奇数坐标和偶数坐标分别维护可到达的区间,然后再从前往后做一遍,每次找到能到达的所有位置中坐标最小的一个走就好了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
typedef long long LL;
const int N=500005;
int n,m,l0[N],r0[N],l1[N],r1[N];
struct data{int x,u,v;}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;
}
bool odd(int x)
{
return abs(x)&1;
}
int main()
{
n=read();m=read();
for (int i=1;i<=n;i++) a[i].x=read(),a[i].u=read()+1,a[i].v=read()-1;
a[0].u=-1;a[0].v=1;
if (odd(a[n].u)) l1[n]=a[n].u,l0[n]=a[n].u+1;
else l0[n]=a[n].u,l1[n]=a[n].u+1;
if (odd(a[n].v)) r1[n]=a[n].v,r0[n]=a[n].v-1;
else r0[n]=a[n].v,r1[n]=a[n].v-1;
for (int i=n-1;i>=0;i--)
{
int d=a[i+1].x-a[i].x;
l0[i]=l0[i+1];r0[i]=r0[i+1];l1[i]=l1[i+1];r1[i]=r1[i+1];
if (odd(d)) std::swap(r0[i],r1[i]),std::swap(l0[i],l1[i]);
l0[i]-=d;l1[i]-=d;r0[i]+=d;r1[i]+=d;
int l=a[i].u,r=a[i].v;
l+=(!odd(l));r-=(!odd(r));
l1[i]=std::max(l1[i],l);r1[i]=std::min(r1[i],r);
l=a[i].u;r=a[i].v;
l+=odd(l);r-=odd(r);
l0[i]=std::max(l0[i],l);r0[i]=std::min(r0[i],r);
}
LL ans=0;int x=0;
for (int i=0;i<n;i++)
{
int d=a[i+1].x-a[i].x,y;
if (odd(x)&&odd(d)||!odd(x)&&!odd(d))
{
int l=std::max(x-d,l0[i+1]),r=std::min(x+d,r0[i+1]);
if (l>r) {puts("NIE");return 0;}
y=l;
}
else
{
int l=std::max(x-d,l1[i+1]),r=std::min(x+d,r1[i+1]);
if (l>r) {puts("NIE");return 0;}
y=l;
}
if (y>=x) ans+=y-x+(d-y+x)/2;
else ans+=(d-x+y)/2;
x=y;
}
printf("%lld",ans);
return 0;
}