旅行问题
环形:2倍空间处理
判断中间有没有油:油的前缀和 - 路程的前缀和
顺时针,前缀和。逆时针,后缀和
顺时针处理:
- 要从后往前枚举:维护的单调队列长度为:n+1
- 因为是前缀和,我们用i后面n个元素的最小值和i比较
- 比较成功之后,i+1为true
- 刚开始q[0] 放下标2*n+1
逆时针处理(同理,注意下标)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e6+100;
typedef long long ll;
ll sum[N],p[N],d[N],q[N];
int n,hh,tt;
bool st[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i]>>d[i];
// shun
for(int i=1;i<=n;i++) p[i+n]=p[i],d[i+n]=d[i];
for(int i=1;i<=2*n;i++)
{
sum[i]=sum[i-1] + p[i]-d[i];
}
// ------
q[0]=2*n+1;
for(int i=2*n;i>=0;i--)
{
if(q[hh]-i+1>n+1) hh++;
if(i<n)
{
if(sum[i]<=sum[q[hh]])
st[i+1]=1;
}
while(hh<=tt && sum[i]<=sum[q[tt]]) tt--;
q[++tt]=i;
}
// -----
d[0]=d[n];
for(int i=2*n;i;i--)
{
sum[i] = sum[i+1] + p[i] - d[i-1];
}
// for(int i=1;i<=2*n;i++)
// {
// cout<<p[i]<<' ';
// }
// cout<<endl;
// cout<<d[0]<<' ';
// for(int i=1;i<=2*n-1;i++)
// cout<<d[i]<<' ';
// cout<<endl;
// for(int i=1;i<=2*n;i++)
// cout<<sum[i]<<' ';
// cout<<endl;
hh=0,tt=0;
q[0]=0;
for(int i=1;i<=2*n+1;i++)
{
if(i-q[hh]+1 > n+1) hh++;
if(i>n)
{
if(sum[q[hh]] >= sum[i])
{
st[i-n - 1] = 1;
}
}
while(hh<=tt && sum[i]<=sum[q[tt]]) tt--;
q[++tt]=i;
}
for(int i=1;i<=n;i++)
{
if(st[i]) cout<<"TAK"<<endl;
else cout<<"NIE"<<endl;
}
return 0;
}