题目描述
小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i,j] = |Hi− Hj|。 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次。他们计划选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行。小 A 和小 B的驾驶风格不同,小 B 总是沿着前进方向选择一个最近的城市作为目的地,而小 A 总是沿着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出 X 公里,他们就会结束旅行。
在启程之前,小 A 想知道两个问题:
对于一个给定的 X=X0,从哪一个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小(如果小 B 的行驶路程为 0,此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值都最小,则输出海拔最高的那个城市。
对任意给定的 X=Xi和出发城市 Si,小 A 开车行驶的路程总数以及小 B 行驶的路程总数。
输入输出格式
输入格式:
第一行包含一个整数 N,表示城市的数目。
第二行有 N 个整数,每两个整数之间用一个空格隔开,依次表示城市 1 到城市 N 的海拔高度,即 H1,H2,……,Hn,且每个 Hi都是不同的。
第三行包含一个整数 X0。
第四行为一个整数 M,表示给定 M 组 Si和 Xi。
接下来的 M 行,每行包含 2 个整数 Si和 Xi,表示从城市 Si出发,最多行驶 Xi公里。
输出格式:
输出共 M+1 行。
第一行包含一个整数 S0,表示对于给定的 X0,从编号为 S0的城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小。
接下来的 M 行,每行包含 2 个整数,之间用一个空格隔开,依次表示在给定的 Si和
Xi下小 A 行驶的里程总数和小 B 行驶的里程总数。
算法
以后补吧
根据海拔升序排列
记录每一个点为基准,海拔距离最近的,以及海拔距离次近的,如果光这样很好弄,但是它还有一个要求:一直向东行驶,也就是说你还得判断排到的i点是否是当前点右边的???
考虑把排序后的节点顺序当作链表:
有没有特殊点,没错,最西边(左边)的点在链表里的所有相邻点都在地理位置的东边(右边),处理完就删除这个点,其实也就是把俩端的点直接相连即可。
然后如何处理出第一近第二近呐?代码复杂,其实思路很简单,
对于当前节点i,设链表里左边两个从右到左为
L1、L2
L
1
、
L
2
右边两个节点从左到有为
R1、R2
R
1
、
R
2
对于最近点从
L1和R1
L
1
和
R
1
中选
如果选择
L1
L
1
那么第二近的就是从
L2和R1
L
2
和
R
1
中选小的
如果选择
R1
R
1
那么第二近的就是从
L1和R2
L
1
和
R
2
中选小的
顺便判断一下选上第一近的没,没选上就是另一个。
根据原题意设置一下初始两个人的第一步路程长
然后倍增出父亲数组,两个人的路程数组,听跳跃的,但是画个图绝对明白了
然后根据两个问题的意思”暴力“就好了
注意
对于一个弱弱来说,额,这道题算不上水题,帮助我很好的运用了lca
因为倍增lca嘛““很容易就觉得结果是对的,过程是有跳跃的,就感觉处理不了过程了
其实不是的。
这道题特色就是
两个人共同走lca
但是分别记录自己的路径,
双人lca
坑就是需要考虑其中一个人可以多走一下下
绕的地方就是排序后,记录各种数据是采用排序前标号,还是排序后标号为主。很绕很绕
代码
以排序后编号为主
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
#define inf 1<<31-1;
//#define a1 aa_1
//#define b1 bb_1
int pre[110000],nxt[110000],mrn1[110000],mrn2[110000],a[110000][22],b[110000][22],f[110000][22],head[110000];//data[110000],
int n;
struct citys{int id;ll h;}c[110000];
bool cmp(const citys s,const citys t){return s.h<t.h;}
void prepare(int x)
{
/*if(pre[x])mrn1[x]=pre[x];
if(nxt[x]&&(c[nxt[x]].h-c[x].h<=c[x].h-c[pre[x]].h||!pre[x]))mrn1[x]=nxt[x];
if(mrn1[x]==pre[x])
{
if(nxt[x])mrn2[x]=nxt[x];
if(pre[pre[x]]&&(c[x].h-c[pre[pre[x]]].h<=c[nxt[x]].h-c[x].h||!nxt[x]))mrn2[x]=pre[pre[x]];
}
else
{
if(pre[x])mrn2[x]=pre[x];
if(nxt[nxt[x]]&&(c[nxt[nxt[x]]].h-c[x].h<=c[x].h-c[pre[x]].h||!pre[x]))mrn2[x]=nxt[nxt[x]];
}
nxt[pre[x]]=nxt[x];
pre[nxt[x]]=pre[x];*/
mrn1[x] = pre[x] && (c[x].h - c[pre[x]].h <= c[nxt[x]].h - c[x].h || !nxt[x]) ? pre[x]:nxt[x];
if(mrn1[x] == pre[x])
mrn2[x] = pre[pre[x]] && (c[x].h - c[pre[pre[x]]].h <= c[nxt[x]].h - c[x].h || !nxt[x]) ? pre[pre[x]] : nxt[x];
else
mrn2[x] = pre[x] && (c[x].h - c[pre[x]].h <= c[nxt[nxt[x]]].h - c[x].h || !nxt[nxt[x]]) ? pre[x] : nxt[nxt[x]];
nxt[pre[x]] = nxt[x];
pre[nxt[x]] = pre[x];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&c[i].h);c[i].id=i;
nxt[i]=i+1;pre[i]=i-1;
if(i==n)nxt[i]=0;
}
sort(c+1,c+n+1,cmp);
for(int i=1;i<=n;i++)
{
head[c[i].id]=i;
}
for(int i=1;i<=n;i++)
prepare(head[i]);
for(int i=1;i<=n;i++)
{
//a first b second
//a 第二近 b 最近
if(mrn2[i])a[i][0]=abs(c[mrn2[i]].h-c[i].h);
if(mrn1[i])b[i][0]=abs(c[mrn1[mrn2[i]]].h-c[mrn2[i]].h);
f[i][0]=mrn1[mrn2[i]];
}
for(int j=1;j<=20;j++)
{
for(int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
a[i][j]=a[i][j-1]+a[f[i][j-1]][j-1];
b[i][j]=b[i][j-1]+b[f[i][j-1]][j-1];
}
}
int x,u;
scanf("%d",&x);
double temp,mirn=inf;int z,xa,xb,ans;
for(int i=1;i<=n;i++)
{
xa=xb=0;z=x;u=head[i];//a路程,b路程,还可以走的路程,出发点的替身
for(int j=20;j>=0;j--)
if(z-a[u][j]-b[u][j]>=0 && f[u][j])
{
z=z-a[u][j]-b[u][j];
xa+=a[u][j];
xb+=b[u][j];
u=f[u][j];
}
if(z-a[u][0]>=0&&mrn2[u])xa+=a[u][0];
//捆绑走整数个,但是接下来a优先一步,说不定还可以走
if(xb==0){temp=inf;}//该次循环的答案
else temp=(double)xa/xb;
if(temp<mirn||(temp==mirn&&c[head[i]].h>c[head[ans]].h))//更小的情况||海拔低的情况
{
mirn=temp;ans=i;
}
}
printf("%d\n",ans);
int whole;scanf("%d",&whole);
while(whole--)
{
scanf("%d%d",&u,&x);
xa=xb=0;z=x;u=head[u];
for(int j=20;j>=0;j--)
if(z-a[u][j]-b[u][j]>=0&&f[u][j])
{
z=z-a[u][j]-b[u][j];
xa+=a[u][j];
xb+=b[u][j];
u=f[u][j];
}
if(z-a[u][0]>=0&&mrn2[u])xa+=a[u][0];
printf("%d %d\n",xa,xb);
}
return 0;
}
RE了一个点,但是我输出来是一样的啊““““`
in:
5
-1000000000 0 -999999999 999999999 1000000000
1000000000
7
1 1000000000
2 1000000000
3 1000000000
4 1000000000
5 1000000000
1 2
2 3
out
2
1000000000 0
999999999 1
0 0
0 0
0 0
0 0
0 0
偷偷附一个0分的以排序前编号为主的算法
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
#define inf 1<<31-1;
//#define a1 aa_1
//#define b1 bb_1
int pre[110000],nxt[110000],mrn1[110000],mrn2[110000],fa[110000][22],fb[110000][22],f[110000][22],data[110000];
int n;
struct citys{int id,h;}a[110000];
bool cmp(const citys s,const citys t){return s.h<t.h;}
void prepare(int u,int i)
{ // p n
if(pre[u])mrn1[i]=a[pre[u]].id;
if((nxt[u]&&a[u].h-a[pre[u]].h>a[nxt[u]].h-a[u].h)||!pre[u])mrn1[i]=a[nxt[u]].id;
if(mrn1[i]==a[pre[u]].id)
{
//pp n
if(nxt[u])mrn2[i]=a[nxt[u]].id;
if((pre[pre[u]]&&a[u].h-a[pre[pre[u]]].h<a[nxt[u]].h-a[u].h)||!nxt[u])mrn2[i]=a[pre[pre[u]]].id;
}
else
{
//p nn
if(pre[u])mrn2[i]=a[pre[u]].id;
if((nxt[nxt[u]]&&a[nxt[nxt[u]]].h-a[u].h<a[u].h-a[pre[u]].h)||!pre[u])mrn2[i]=a[nxt[nxt[u]]].id;
}
nxt[pre[u]]=nxt[u];
pre[nxt[u]]=pre[u];
}
void init()
{
//a first b second
//a 第二近 b 最近
for(int i=1;i<=n;i++)
{
if(mrn2[i])fa[i][0]=abs(data[mrn2[i]]-data[i]);
if(mrn1[i])fb[i][0]=abs(data[mrn1[mrn2[i]]]-data[mrn2[i]]);
f[i][0]=mrn1[mrn2[i]];
}
}
void getst()
{
init();
for(int j=1;j<=20;j++)
for(int i=1;i<=n;i++)
{
f[i][j]= f[f[i][j-1]][j-1];
fa[i][j]=fa[i][j-1]+fa[f[i][j-1]][j-1];
fb[i][j]=fb[i][j-1]+fb[f[i][j-1]][j-1];
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].h);a[i].id=i;data[i]=a[i].h;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
if(i==n)nxt[i]=0;
else
{pre[i]=i-1;nxt[i]=i+1;}
}
for(int i=1;i<=n;i++)
prepare(i,a[i].id);
//for(int i=1;i<=n;i++)
//cout<<i<<" "<<pre[i]<<" "<<nxt[i]<<" "<<endl;
getst();
/
int x0;scanf("%d",&x0);
double mirn=inf;int ans=0;
for(int i=1;i<=n;i++)
{
int aa_1=0,bb_1=0,z=x0,u=i;//a路程,b路程,还可以走的路程,出发点的替身
for(int j=20;j>=0;j--)//倍增思想
{
if(f[u][j] && z-fa[u][j]-fb[u][j]>=0)//???,可以走
{
aa_1+=fa[u][j],bb_1+=fb[u][j];
z=z-fa[u][j]-fb[u][j];
u=f[u][j];
}
}
if(z-fa[u][0]>=0&&mrn2[u]){aa_1+=fa[u][0];}//捆绑走整数个,但是接下来a优先一步,说不定还可以走
double temp;//该次循环的答案
if(bb_1==0) {temp=inf;}
else
{temp=(double)(aa_1/bb_1);}
if(mirn>temp||(temp==mirn&& data[i]<data[ans]))//更小的情况||海拔低的情况
{
ans=i;mirn=temp;
}
}
printf("%d\n",ans);
int q,s,x1;scanf("%d",&q);
while(q--)
{
scanf("%d%d",&s,&x1);
int aa_1=0,bb_1=0;
for(int j=20;j>=0;j--)
{
if(f[s][j]&&x1-fa[s][j]-fb[s][j]>=0)
{
x1=x1-fa[s][j]-fb[s][j];
aa_1+=fa[s][j];
bb_1+=fb[s][j];
s=f[s][j];
}
}
if(x1-fa[s][0]>=0&&mrn2[s])aa_1+=fa[s][0];
printf("%d %d\n",aa_1,bb_1);
}
/*for(int i=1;i<=n;i++)
{
cout<<"~~~~~~~~~~"<<i<<"~~~~~~~~~~"<<endl;
for(int j=0;j<=20;j++)
{
cout<<fa[i][j]<<" ";
}
cout<<endl;
for(int j=0;j<=20;j++)
{
cout<<fb[i][j]<<" ";
}
cout<<endl;
}*/
return 0;
}