AcWing1088.旅行问题
代码好像还有一点问题
/*
数组没开够,爆零两行泪
longlong开成int,爆零两行泪
多组忘清空,爆零两行泪
dp 没初值,爆零两行泪
深搜没边界,爆零两行泪
广搜忘出队,爆零两行泪
输入没加 &,爆零两行泪
模数没看见,爆零两行泪
-1 不输出,爆零两行泪
越界不特判,爆零两行泪
线段树开一倍,爆零两行泪
无向变有向,爆零两行泪
题意没审清,爆零两行泪
文件名起错,爆零两行泪
调试忘删除,爆零两行泪
没用freopen,爆零两行泪
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+16;//破幻成殓,卡二倍空间
int n;
int o[N],d[N],q[N];//q[hh]是最小区间和的下标
ll s[N];
bool ans[N];//标记数组
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>o[i]>>d[i];
}
for(int i=1;i<=n;i++){
s[i]=s[i+n]=o[i]-d[i];//把油量和距离一起处理;
}
//顺时针处理 ,也就是从1~n
int hh=0,tt=-1;
for(int i=1;i<=n*2;i++) s[i]+=s[i-1];
for(int i=n*2;i>=1;i--){
if(hh<=tt&&q[hh]>=i+n) hh++;//数超范围
while(hh<=tt&&s[q[tt]>=s[i]]) tt--;//最小值先更新再求
q[++tt]=i;
if(i<=n){
if(s[q[hh]]>=s[i-1]) ans[i]=true;
}
}
// 逆时针数
hh=0,tt=-1;
d[0]=d[n];
for(int i=1;i<=n;i++) s[i]=s[i+n]=o[i]-d[i-1];
for(int i=1;i<=n*2;i++) s[i]+=s[i-1];
for(int i=1;i<=n*2;i++){
if(hh<=tt&&q[hh]<i-n) hh++;//超出范围,必须在i-1到i-n
if(i>n){
if(s[q[hh]]<=s[i]) ans[i-n]=true;//即s[i]-s[q[hh]]>=0油还有剩余,能到i
}
while(hh<=tt&&s[q[tt]]<=s[i]) tt--;//最小值先求再更新
q[++tt]=i;
}
for(int i=1;i<=n;i++){
if(ans[i]) puts("TAK");
else puts("NIE");
}
return 0;
}
/*
考虑处理环行;
可以枚举从i点出发,再到达i点 i∈[1,n];
大概是这样
/----------------->|
/----------------->|
/----------------->|
(省略)
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
对于从1开始又等价于s[i]>=0, i∈[1,n],s[]是前缀和数组;
也就是中途油箱中油量不能为负
也就是对于每个点,找区间最小值,若最小值>=0,则安全
按照惯例,预处理前缀和
正反两个方向扫描
对于区间i,j,每个s[i]大小是固定的,所以要求s[j]的最小值
*/