題意:每次求和當前點連線斜率最大的點,然後求最小公共祖先。
對於當前點i,記和i點連線斜率最大的點爲r[i],則r[i]一定是i+1或者i+1的祖先。於是預處理出r[]數組然後建樹求LCA
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <stack> #define clr(A) memset(A,0,sizeof(A)) #define mm 100005 using namespace std; typedef long long LL; LL x[mm],y[mm]; int r[mm],d[mm]; stack<int > S; vector<pair<int, int > > by[mm]; int ans[mm],F[mm]; vector<int> E[mm]; int vis[mm]; void insert(int i,int j){ F[i] = j; } int Fat(int k){ return F[k]==k?F[k]:F[k] == Fat(k); } void dfs(int k) { vis[k] = 1; for(int i = 0;i<E[k].size();i++){ dfs(E[k][i]); insert(E[k][i],k); } for(int i = 0;i<by[k].size();i++) if(vis[by[k][i].first]){ ans[by[k][i].second] = Fat(by[k][i].first); } } int main() { int n; freopen("CF.in","r",stdin); scanf("%d",&n); for(int i = 1;i<=n;i++) scanf("%I64d%I64d",x+i,y+i); while(!S.empty()) S.pop(); S.push(n);r[n] = -1; for(int i = n-1;i>=1;i--){ double k = ((double)y[i]-y[i+1])/(x[i]-x[i+1]); int u = r[i] = i + 1; while(u != n && ((double)y[i] - y[u])/(x[i] - x[u]) <((double)y[i] - y[r[u]])/(x[i] - x[r[u]])) u = r[u]; r[i] = u; S.push(i); E[u].push_back(i); } int m,a,b; scanf("%d",&m); for(int i =1;i<=m;i++){ scanf("%d%d",&a,&b); by[b].push_back(make_pair(a,i)); by[a].push_back(make_pair(b,i)); } for(int i =1;i<=n;i++) F[i] = i; clr(vis); dfs(n); for(int i = 1;i<=m;i++) printf("%d ",ans[i]); return 0; }