D:
建树,然后倍增法求最近公共祖先。
建树的方法:
考虑当前这座山i能飞到最右边是哪座?一定是与这座山斜率最大的,那么父节点就是它了。
fa[]表示父节点,先比较i+1与fa[i+1]关于i的斜率,如果前者小于后者。那么就要去比较fa[i+1],fa[fa[i+1]]。直到前者大于等于后者。
这里的复杂度是O(n)。因为如果i+1的斜率是小于fa[i+1]的,那么i的父节点必然是i+1后面的节点。那么在以后的比较中,i+1这个点是不可能被访问到的,因为fa[i]>i+1。
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <sstream>
#include <stdio.h>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 100024
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<int,int> PI;
const int INF = 0x3fffffff;
const int MOD = 1000000007;
/*-----------code------------*/
map<ll,int> R;
double x[N],y[N];
int fa[N],dp[N][20];
vector<int> e[N];
const int M=17;
int dep[N];
void dfs(int u,int par,int h=0){
dp[u][0]=par;
dep[u]=h;
for(int i=1;i<=M;i++) dp[u][i]=dp[dp[u][i-1]][i-1];
for(int i=0;i<e[u].size();i++){
int v=e[u][i];
dfs(v,u,h+1);
}
}
int find(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
int dif=dep[u]-dep[v];
for(int i=0;i<=M;i++) if(dif&(1<<i)){
u=dp[u][i];
}
if(u!=v){
for(int i=M;i>=0;i--){
if(dp[u][i]!=dp[v][i]){
u=dp[u][i], v=dp[v][i];
}
}
u=dp[u][0];
}
return u;
}
double cal(int i,int j){
return (y[j]-y[i])/(x[j]-x[i]);
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf %lf",&x[i],&y[i]);
}
int p=n;
fa[n]=n;
for(int i=n-1;i>=1;i--){
int a=i+1,b=fa[i+1];
while(cal(i,a)<cal(i,b)){
a=b;
b=fa[b];
}
fa[i]=a;
e[a].push_back(i);
}
dfs(n,n);
int m;
scanf("%d",&m);
while(m--){
int u,v;
scanf("%d%d",&u,&v);
printf("%d ",find(u,v));
}
return 0;
}