CF238_DIV1_D

題意:每次求和當前點連線斜率最大的點,然後求最小公共祖先。

對於當前點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;
}

發佈了33 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章