传送门:【CodeForces】406D Hill Climbing
题目分析:首先用单调栈维护凸包,以此得到树边并建树,然后就是求LCA了,我懒得写倍增法,于是乎写了树链剖分版的LCA,可以说LCA是树链剖分的副产物,顺便求求LCA是毫无问题的~。
当然最快的还是离线Tarjan。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std ;
typedef long long LL ;
#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define For( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define rev( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define mid ( ( l + r ) >> 1 )
#define root 1 , 1 , n
const int MAXN = 100005 ;
const int MAXE = 200005 ;
struct Edge {
int v ;
Edge* next ;
} E[MAXE] , *H[MAXN] , *edge ;
struct Point {
LL x , y ;
int idx ;
Point () {}
Point ( LL x , LL y ) : x ( x ) , y ( y ) {}
Point operator - ( const Point& p ) const {
return Point ( x - p.x , y - p.y ) ;
}
void input ( int index ) {
scanf ( "%I64d%I64d" , &x , &y ) ;
idx = index ;
}
} p[MAXN] , S[MAXN] ;
int top[MAXN] ;
int siz[MAXN] ;
int son[MAXN] ;
int pre[MAXN] ;
int dep[MAXN] ;
int point ;
int n , q ;
void clear () {
edge = E ;
siz[0] = 0 ;
point = 0 ;
clr ( H , 0 ) ;
clr ( son , 0 ) ;
clr ( pre , 0 ) ;
clr ( top , 0 ) ;
}
void addedge ( int u , int v ) {
edge -> v = v ;
edge -> next = H[u] ;
H[u] = edge ++ ;
}
void dfs ( int u ) {
siz[u] = 1 ;
son[u] = 0 ;
travel ( e , H , u ) {
int v = e -> v ;
if ( v == pre[u] ) continue ;
pre[v] = u ;
dep[v] = dep[u] + 1 ;
dfs ( v ) ;
if ( siz[v] > siz[son[u]] ) son[u] = v ;
}
}
void rewrite ( int u , int top_element ) {
top[u] = top_element ;
if ( son[u] ) rewrite ( son[u] , top_element ) ;
travel ( e , H , u ) {
int v = e -> v ;
if ( v != son[u] && v != pre[u] ) rewrite ( v , v ) ;
}
}
int query ( int x , int y ) {
while ( top[x] != top[y] ) {
if ( dep[top[x]] > dep[top[y]] ) x = pre[top[x]] ;
else y = pre[top[y]] ;
}
if ( dep[x] < dep[y] ) return x ;
else return y ;
}
int cross ( const Point& a , const Point& b ) {
return a.x * b.y - a.y * b.x > 0 ;
}
void solve () {
int x , y ;
clear () ;
For ( i , 1 , n ) p[i].input ( i ) ;
rev ( i , n , 1 ) {
while ( point > 1 && cross ( S[point - 1] - p[i] , S[point - 2] - p[i] ) ) -- point ;
S[point ++] = p[i] ;
if ( point > 1 ) {
addedge ( S[point - 2].idx , S[point - 1].idx ) ;
//printf ( "%d -> %d\n" , S[point - 2].idx , S[point - 1].idx ) ;
}
}
dfs ( n ) ;
rewrite ( n , n ) ;
scanf ( "%d" , &q ) ;
while ( q -- ) {
scanf ( "%d%d" , &x , &y ) ;
printf ( "%d\n" , query ( x , y ) ) ;
}
}
int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}