确定了起点和方向之后,旅行的过程就确定了,到达i点的花费<=到i点之间的油料数量就是题目的限制条件.
由于是绕圈问题,我们可以把序列复制相接,转化成序列上的问题.
设
sum[j]
表示到
j
之前所得油料数量
sum[j]−sum[i]>=dis[j]−dis[i]
移项得到:
sum[j]−dis[j]>=sum[i]−dis[i]
.
那么只要保证
sum[j]−dis[j]
的最小值满足条件即可.
问题就转化为了求区间最值问题,根据起点的移动规律,可以确定每次
j
<script type="math/tex" id="MathJax-Element-90">j</script>的范围只往前移动了1,那么我们可以通过单调队列来求出最值,从而得到答案
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=2e6+5;
int d[M],p[M],n,Q[M],id[M];
ll sum[M],dis[M];
bool f[M];
inline void rd(int &res){
res=0;char c;
while(c=getchar(),c<48);
do res=(res<<1)+(res<<3)+(c^48);
while(c=getchar(),c>=48);
}
void solve(int s){
int i,j,k;
sum[0]=0;
for(i=1;i<=n*2;i++){
sum[i]=sum[i-1]+p[i-1];//sum[i]表示从1到i能得到的油量,不包括i
dis[i]=dis[i-1]+d[i+s];//从1到i的距离和
}
/*
for i
j->[i+1,i+n] sum[j]-sum[i]>=dis[j]-dis[i]
sum[j]-dis[j]>=sum[i]-dis[i].
Min(sum[j]-dis[j])>=sum[i]-dis[i]
Push k -> pop val[j]>=val[k]
*/
int L=0,R=-1;
for(i=2;i<=n+1;i++){
while(R>=L&&sum[Q[R]]-dis[Q[R]]>=sum[i]-dis[i])R--;
Q[++R]=i;
}
for(i=1;i<=n;i++){//判断i点是否可行
while(L<=R&&Q[L]<i+1)L++;
if(L<=R){
k=Q[L];
if(sum[k]-dis[k]>=sum[i]-dis[i])f[id[i]]=true;
}
while(R>=L&&sum[Q[R]]-dis[Q[R]]>=sum[i+n+1]-dis[i+n+1])R--;
Q[++R]=i+n+1;
}
}
int main(){
int i,j,k;
rd(n);
for(i=1;i<=n;i++){
id[i]=i;
rd(p[i]),rd(d[i]);
p[i+n]=p[i];
d[i+n]=d[i];
}
solve(-1);
for(i=1;i<=n;i++){
swap(d[i],d[2*n-i+1]);
swap(p[i],p[2*n-i+1]);
id[i]=n-i+1;
}
solve(0);
for(i=1;i<=n;i++){
if(f[i])puts("TAK");
else puts("NIE");
}
return 0;
}