NOIP2012 开车旅行 倍增

题意:两人轮流开车,求解一些问题(题目已经讲得很清楚了)
题解:

  • 首先预处理出每座城市的最近点和次近点(可以用双向链表做,排序后从左到右依次找,找了之后就删掉)
  • 然后预处理倍增,注意这时的城市已经是排序过后的了,可以转化成原来的排列进行操作也可以直接在新排列上进行。
  • 接下来模拟就好咯

具体看代码,这次写的有点复杂其实是因为我不会指针再加上作死

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN = 100001;
const double INF = 2147483647;

struct Node{
    int Height, Num;
    int Pre, Nxt;
    int Next[2];
}City[MAXN];

int N, M, x0, Head[MAXN];
int Dis_A[MAXN][20], Dis_B[MAXN][20], City_Jumper[MAXN][20];


inline int read(){
    int k = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){k = k*10 + ch - '0'; ch = getchar();}
    return k * f;
}

inline void Build_Link(){
    for(int i = 1; i <= N; i++){
        City[i].Pre = i - 1, City[i].Nxt = i + 1;
        Head[City[i].Num] = i;
    }
    City[1].Pre = City[N].Nxt = 0;
    for(int i = 1; i <= N; i++){
        int Cur = Head[i]; //从左到右的城市 
        if(City[Cur].Pre){
            Cur = City[Cur].Pre; //前一个 
            City[Head[i]].Next[0] = Cur;
            if(City[Cur].Pre){
                Cur = City[Cur].Pre; //再前一个 
                if(City[Head[i]].Height - City[Cur].Height < 
                abs(City[Head[i]].Height - City[City[Head[i]].Next[0]].Height)){

                    City[Head[i]].Next[1] = City[Head[i]].Next[0];
                    City[Head[i]].Next[0] = Cur;
                }
                else{
                    City[Head[i]].Next[1] = Cur;
                }
            }
        }
        Cur = Head[i];
        if(City[Cur].Nxt){
            Cur = City[Cur].Nxt; //后一个 
            if(City[Cur].Height - City[Head[i]].Height < 
            abs(City[Head[i]].Height - City[City[Head[i]].Next[0]].Height) 
            || !City[Head[i]].Next[0]){

                City[Head[i]].Next[1] = City[Head[i]].Next[0];
                City[Head[i]].Next[0] = Cur;
            }
            else if(City[Cur].Height - City[Head[i]].Height < 
            abs(City[Head[i]].Height - City[City[Head[i]].Next[1]].Height) 
            || !City[Head[i]].Next[1]){

                City[Head[i]].Next[1] = Cur;
            }
            if(City[Cur].Nxt){
                Cur = City[Cur].Nxt; //再后一个 
                if(City[Cur].Height - City[Head[i]].Height < 
                abs(City[Head[i]].Height - City[City[Head[i]].Next[0]].Height)){

                    City[Head[i]].Next[1] = City[Head[i]].Next[0];
                    City[Head[i]].Next[0] = Cur;
                }
                else if(City[Cur].Height - City[Head[i]].Height < 
                abs(City[Head[i]].Height - City[City[Head[i]].Next[1]].Height) 
                || !City[Head[i]].Next[1]){

                    City[Head[i]].Next[1] = Cur;
                }
            }
        }
        City[City[Head[i]].Pre].Nxt = City[Head[i]].Nxt;
        City[City[Head[i]].Nxt].Pre = City[Head[i]].Pre;
    }
    return;
}

void Build_Multiply(){
    for(int i = 1; i <= N; i++){
        City_Jumper[i][0] = City[City[i].Next[1]].Next[0];
        if(City[i].Next[0]){
            Dis_A[i][0] = abs(City[City[i].Next[1]].Height - City[i].Height);
        }
        if(City_Jumper[i][0]){
            Dis_B[i][0] = abs(City[City_Jumper[i][0]].Height - 
                                                City[City[i].Next[1]].Height);
        }
    }
    for(int j = 1; j <= 18; j++){
        for(int i = 1; i <= N; i++){
            City_Jumper[i][j] = City_Jumper[City_Jumper[i][j - 1]][j - 1];
            Dis_A[i][j] = Dis_A[i][j - 1] + Dis_A[City_Jumper[i][j - 1]][j - 1];
            Dis_B[i][j] = Dis_B[i][j - 1] + Dis_B[City_Jumper[i][j - 1]][j - 1];
        }
    }
    return;
}

int Solve_Problem_1(){
    long long DisA_Already, DisB_Already;
    int Cur, Ans_City = 0;
    double Ans_Val = INF;
    for(int i = 1; i <= N; i++){
        Cur = Head[i]; DisA_Already = DisB_Already = 0;
        for(int j = 18; j >= 0; j--){
            if(City_Jumper[Cur][j] 
            && DisA_Already + DisB_Already + Dis_A[Cur][j] + Dis_B[Cur][j] <= x0){
                DisA_Already += Dis_A[Cur][j];
                DisB_Already += Dis_B[Cur][j];
                Cur = City_Jumper[Cur][j];
            }
        }
        if(City[Cur].Next[1]
         && DisA_Already + DisB_Already + Dis_A[Cur][0] <= x0){
            DisA_Already += Dis_A[Cur][0];
        }
//      printf("%d %lf\n", Head[i], (double)DisA_Already / DisB_Already);
        if(DisB_Already && Ans_Val > (double)DisA_Already / DisB_Already){
            Ans_Val = (double)DisA_Already / DisB_Already;
            Ans_City = i;
        }
    }
    return Ans_City;
}

void Solve_Problem_2(int x0, int Cur){
    long long DisA_Already = 0, DisB_Already = 0;
    for(int j = 18; j >= 0; j--){
        if(City_Jumper[Cur][j] 
        && DisA_Already + DisB_Already + Dis_A[Cur][j] + Dis_B[Cur][j] <= x0){
            DisA_Already += Dis_A[Cur][j];
            DisB_Already += Dis_B[Cur][j];
            Cur = City_Jumper[Cur][j];
        }
    }
    if(City[Cur].Next[1] && DisA_Already + DisB_Already + Dis_A[Cur][0] <= x0){
        DisA_Already += Dis_A[Cur][0];
    }
    printf("%lld %lld\n", DisA_Already, DisB_Already);
    return;
}

inline bool cmp(Node a, Node b){
    return a.Height < b.Height;
}

int main(){
    N = read();
    for(int i = 1; i <= N; i++){
        City[i].Height = read();
        City[i].Num = i;
    }
    sort(City + 1, City + N + 1, cmp);
    Build_Link(); Build_Multiply();
    x0 = read(), M = read();
    //Solve Problem 1
    int Ans1 = Solve_Problem_1();
    printf("%d\n", Ans1);
    //Solve Problem 2
    for(int i = 1; i <= M; i++){
        int s = read(), x = read();
        Solve_Problem_2(x, Head[s]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值