Luogu P1081 [NOIp2012]開車旅行


題目描述 傳送門


很容易想到O(n2) 暴力預處理在每個城市時小A和小B分別要到達的另一個城市和距離。再暴力O(nm) 求每一個詢問。這樣可以騙到70分。
預處理時可以用平衡樹,具體操作是將每一座城市從西往東一個插入樹,再尋找與它距離最近的,仔細想一下就知道怎麼找了。因爲是倒着插,所以樹中的一定是此城市西邊的。(平衡樹可以用STL的set)
作爲蒟蒻的我以前只知道倍增可以搞st表和樹上lca,然而不知道倍增還可以這樣用,看了網上的題解才曉得,看來我對倍增的理解還不夠深刻。
至於倍增的地方自己可以YY出來(然而自從我學會樹鏈剖分就沒怎麼用過倍增了,所以寫了好久也寫的好爛…)
純自己寫的(爛的話不要見笑)
代碼

#include<cstdio>
#include<iostream>
#include<cstring>
#include<set>
#include<algorithm>
#include<climits>
#include<cmath>
#define INF INT_MAX-1
using namespace std;
const int maxn=100005;
typedef pair<int,int> pii;
set<pii>s;
int f[maxn][20][2],g[maxn][20],h[maxn],dist1[maxn],dist2[maxn],first[maxn],second[maxn],I;
bool cmp(const pii&a,const pii&b){
    return abs(a.first-h[I])==abs(b.first-h[I])?a.first<b.first:abs(a.first-h[I])<abs(b.first-h[I]);
}
void getfs(int &i){
    set<pii>::iterator itl=s.find(pii(h[i],i));
    set<pii>::iterator itr=itl;
    pii a[4];
    int cnt=0;
    if(itl--!=s.begin()){
        a[cnt++]=*itl;    
        if(itl--!=s.begin()) a[cnt++]=*itl;
    }
    if(++itr!=s.end()){
        a[cnt++]=*itr;
        if(++itr!=s.end()) a[cnt++]=*itr;
    }
    I=i;
    sort(a,a+cnt,cmp);
    if(cnt<=1) dist2[i]=INF;
    else{
        dist2[i]=abs(a[1].first-h[i]);
        second[i]=a[1].second;
    }
    if(cnt==0) dist1[i]=INF;
    else{
        dist1[i]=abs(a[0].first-h[i]);
        first[i]=a[0].second;
    }
}
int main(){    
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%d",&h[i]);
    for(int i=n;i>0;i--){
        s.insert(pii(h[i],i));
        getfs(i);
    }
    for(int i=1;i<=n;i++){
        g[i][0]=first[second[i]];
        f[i][0][1]=dist2[i];
        f[i][0][0]=dist1[second[i]];
    }
    for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++){
            g[i][j]=g[g[i][j-1]][j-1];
            if(f[i][j-1][0]==INF||f[g[i][j-1]][j-1][0]==INF) f[i][j][0]=INF;
            else f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];
            if(f[i][j-1][1]==INF||f[g[i][j-1]][j-1][1]==INF) f[i][j][1]=INF;
            else f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];
        }
    int X;
    cin>>X;
    double ansvalue=INF+1;
    int ans;
    for(int i=1;i<=n;i++){
        int x=X,b=i,distA=0,distB=0;
        for(int j=19;j>=0;--j) if(f[b][j][0]!=INF&&f[b][j][1]!=INF&&f[b][j][0]+f[b][j][1]<=x){
            x-=f[b][j][0]+f[b][j][1];
            distA+=f[b][j][1];
            distB+=f[b][j][0];
            b=g[b][j];
        }
        if(f[b][0][1]<=x) distA+=f[b][0][1];
        double value;
        if(distB==0) value=INF;
        else value=1.0*distA/distB;
        if(value<ansvalue||(fabs(value-ansvalue)<=1e-9&&h[ans]<h[i])) ansvalue=value,ans=i;
    }
    cout<<ans<<endl;
    int m;
    cin>>m;
    for(int i=0;i<m;i++){
        int b,x,distA=0,distB=0;
        scanf("%d%d",&b,&x);
        for(int j=19;j>=0;--j) if(f[b][j][0]!=INF&&f[b][j][1]!=INF&&f[b][j][0]+f[b][j][1]<=x){
            x-=f[b][j][0]+f[b][j][1];
            distA+=f[b][j][1];
            distB+=f[b][j][0];
            b=g[b][j];
        }
        if(f[b][0][1]<=x) distA+=f[b][0][1];
        printf("%d %d\n",distA,distB);
    }
    return 0;
}
發佈了59 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章