有一条地铁线路,n段路,n+1个站,每段路可以同时交汇走两辆车或只能走一辆车,
每个站可以停车,停车不占用线路,
现在每隔Kmin发一次车,分别从起点/终点开向终点/起点,
每段路要走的时间已知,求两个方向的辆车运行时间总和最小
因为是每隔Km分钟发一次车,因此考虑在mod K的情况下做,
先把双向的线路忽略,只考虑单向的,
设第i段路要走 Ai 分钟,第i站的停站时间分别为 qi,pi
两个方向的车不会相交,当且仅当:
(∑q0...i−1+∑A1..i−1,∑q0...i−1+∑A1..i)
与区间
(∑pi...n+∑Ai..n,∑pi...n+∑Ai−1..n)
没有交点,
把第二个式子换个方式写:
(N−∑p0...i−1−∑A1..i−1,N−∑p0...i−1−∑A1..i)
显然,式子是在mod意义下的,同时也可以通过调节使得N为K的倍数,所以整理后即为:
(∑q0...i−1+∑A1..i−1,∑q0...i−1+∑A1..i)
与区间
(−∑p0...i−1−∑A1..i−1,−∑p0...i−1−∑A1..i)
没有交点,
先做q+p的前缀和,设为 Si
判断区间相交可以用判断端点是否被包含,写出不等式后发现,我们只要保证
∑q0...i−1+∑p0...i−1 不在区间 (−2∑A1..i−1,−2∑A1..i) 内即可,
也就是,在数轴上走,要保证第i个时刻不在某个区间内,
我们的目的是使 Sn−S0 最小,(这个不取模)
发现每次如果要走,肯定是走到左端点上,
这个直接用线段树做即可,每次查询一个区间最小值,再区间更改权值,
复杂度: O(nlog(n))
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef long long LL;
const int N=100500;
const LL INF=1e17;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,n1;
LL a[N],ans;
bool az[N];
int L[N],R[N];
struct Data
{
int l,r;
LL v,la;
}b[N*100];
int root,b0;
void doit(int l,int r,int e,int K=1)
{
if(!e||b[e].la<0)return;
b[e].v=b[e].la;
if(l!=r)
{
if(b[e].l||K)b[b[e].l?b[e].l:(b[e].l=++b0)].la=b[e].la;
if(b[e].r||K)b[b[e].r?b[e].r:(b[e].r=++b0)].la=b[e].la;
}
b[e].la=-1;
}
void change(int l,int r,int &e,int l1,int r1,LL l2)
{
if(l>r||l1>r1)return;
if(!e)e=++b0;
if(l1<=l&&r<=r1)
{
b[e].la=l2;
doit(l,r,e);
return;
}
int t=(l+r)>>1;
doit(l,t,b[e].l),doit(t+1,r,b[e].r);
if(l1<=t)change(l,t,b[e].l,l1,r1,l2);
if(t1,r,b[e].r,l1,r1,l2);
b[e].v=min(b[b[e].l].v-(LL)t+r,b[b[e].r].v);
}
LL find(int l,int r,int e,int l1,int r1)
{
if(!e||rr1)return INF;
doit(l,r,e);
if(l1<=l&&r<=r1)return b[e].v-(LL)r+r1;
int t=(l+r)>>1;
LL ans=INF,ans1=INF;
if(l1<=t)ans=find(l,t,b[e].l,l1,r1);
if(t1,r,b[e].r,l1,r1);
return min(ans,ans1);
}
LL findS(int l,int r,int e)
{
if(!e)return INF;
doit(l,r,e,0);
if(l==r)return b[e].v;
int t=(l+r)>>1;
LL ans=INF,ans1=INF;
ans=findS(l,t,b[e].l);
ans1=findS(t+1,r,b[e].r);
return min(ans,ans1);
}
int main()
{
int q,w;
read(n),read(n1);
fo(i,1,n)
{
a[i]=a[i-1]+(LL)read(q);az[i]=read(w)-1;
if(q*2>n1&&w==1)return printf("-1\n"),0;
if(w==1)L[i]=(n1-2LL*a[i]%n1+1)%n1,R[i]=(n1-2LL*a[i-1]%n1-1)%n1;
}
b0=1;b[0].v=INF,b[1].v=0;
b[0].la=-1,b[1].la=0;
root=1;
fo(i,1,n)if(!az[i])
{
if(L[i]<=(R[i]+1)%n1)
{
LL t=find(0,n1-1,root,L[i],(R[i]+1)%n1);
change(0,n1-1,root,L[i],R[i],INF);
change(0,n1-1,root,(R[i]+1)%n1,(R[i]+1)%n1,t);
}
else
{
LL t=find(0,n1-1,root,L[i],n1-1)+(R[i]+1LL)%n1+1LL;
change(0,n1-1,root,L[i],n1-1,INF);
LL t1=find(0,n1-1,root,0,(R[i]+1)%n1);
change(0,n1-1,root,0,(R[i]+1)%n1,INF);
change(0,n1-1,root,(R[i]+1)%n1,(R[i]+1)%n1,min(t,t1));
}
}
ans=findS(0,n1-1,root)+a[n]*2LL;
printf("%lld\n",ans);
return 0;
}