AcWing1088.旅行问题

link

代码好像还有一点问题

/*
数组没开够,爆零两行泪
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]的最小值 
*/
posted @ 2020-10-31 19:24  actypedef  阅读(33)  评论(0编辑  收藏  举报