[noip 2012] 开车旅行


set+map+倍增,不能吐槽更多。


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
    return;
}
template<class Num>void write(Num x)
{
    if(!x) {putchar('0');return;}
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    while(sl) putchar(s[--sl]);
}

const int maxn = 1e5 + 50, logN = 18;

int n, m, H[maxn], S, x, l;
std::set<int> set;
std::map<int,int> map;
int step[maxn][logN];
long long walk[maxn][logN][2];
int next[maxn][2], len[maxn][2];

void init()
{
    std::set<int>::iterator pre, sur;
    static std::pair<int,int> t[5];

    read(n);

    for(int i = 1; i <= n; i++)
        read(H[i]), map[H[i]] = i;

    for(int i = n; i >= 1; i--)
    {
        l = 0, set.insert(H[i]);
        pre = sur = set.lower_bound(H[i]);

        if(pre != set.begin())
        {
            t[++l].second = *(--pre);

            if(pre != set.begin())
                t[++l].second = *(--pre);
        }
        if(++sur != set.end())
        {
            t[++l].second = *sur;

            if(++sur != set.end())
                t[++l].second = *sur;
        }
        for(int j = 1; j <= l; j++)
            t[j].first = abs(H[i] - t[j].second);

        std::sort(t + 1, t + l + 1);

        if(l >= 1)
        {   
            next[i][1] = map[t[1].second];
            len[i][1] = t[1].first;
        }
        if(l >= 2)
        {
            next[i][0] = map[t[2].second];
            len[i][0] = t[2].first;
        }

        step[i][0] = next[next[i][0]][1];
        walk[i][0][0] = len[i][0];
        walk[i][0][1] = len[next[i][0]][1];

        for(int j = 1; j < logN; j++)
        {
            step[i][j] = step[step[i][j - 1]][j - 1];
            walk[i][j][0] = walk[i][j - 1][0] + walk[step[i][j - 1]][j - 1][0];
            walk[i][j][1] = walk[i][j - 1][1] + walk[step[i][j - 1]][j - 1][1];
        }
    }
}

void query(int s,int lim,long long &a,long long &b)
{
    for(int i = logN - 1; i >= 0; i--)
    {
        if(walk[s][i][0] + walk[s][i][1] <= lim)
        {
            lim -= walk[s][i][0] + walk[s][i][1];
            a += walk[s][i][0], b += walk[s][i][1];
            s = step[s][i];
        }
    }
    if(len[s][0] <= lim) a += len[s][0];
}
void solve()
{
    long long distA = 1, distB = 0;
    long long A, B;

    read(x), S = 0;
    for(int i = 1; i <= n; i++)
    {
        query(i, x, A = 0, B = 0);

        if(A * distB < B * distA)
        {
            distA = A, distB = B;
            S = i;
        }
    }
    write(S), puts("");

    read(m);
    for(int i = 1; i <= m; i++)
    {
        read(S), read(x);

        query(S, x, A = 0, B = 0);

        write(A), putchar(' ');
        write(B), puts("");
    }
}

int main()
{

    init();

    solve();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值