【倍增】【set】[NOIP2012] codevs1199 开车旅行

来源:互联网 发布:网页编程课程设计 编辑:程序博客网 时间:2024/05/01 22:25

题目点这里


这题的复杂度基本就在预处理找在每个点A、B分别要开去哪上面了 = =倍增其实很水……

用set维护高度。因为只能从前往后,所以从后往前插入,然后取其前两个和后两个用他们之间的距离排个序,距离最小的是B去的地方,第二小是A去的地方。

记A+B各开一次为一轮。然后令f[i][j]为从i出发,开了2^j轮去了哪。fa[i][j]、fb[i][j]分别表示从a、b出发走2^j轮后开的距离。

于是

f[i][j] = f[f[i][j -1]][j -1];

fa[i][j] = fa[i][j -1] +fa[f[i][j -1]][j -1];

fb[i][j] = fb[i][j -1] +fb[f[i][j -1]][j -1];

然后询问和倍增LCA差不多 = = 注意考虑最后只有A能走……对于第一个问枚举起点即可。

另外vijos上的数据很厉害啊,估计得手写treap了2333


#include <cstdio>#include <iostream>#include <set>#include <algorithm>using namespace std;int N, x0, M, S, x1;struct city {    int pos, high;    bool operator < (const city &b) const {        return high < b.high;    }}c[100005];set <city> s;struct temp {    int pos, dif;    bool operator < (const temp &b) const {        if (dif != b.dif) return dif < b.dif;        return c[pos].high < c[b.pos].high;    }}t[5];int nexta[100005], nextb[100005], f[100005][20];long long fa[100005][20], fb[100005][20];inline void Find(int i){    set <city> :: iterator it = s.find(c[i]);        int add = 0;    if (it != s.begin()) {        -- it; t[++ add] = (temp) { it -> pos, abs(it -> high - c[i].high) };        if (it != s.begin()) {            -- it; t[++ add] = (temp) { it -> pos, abs(it -> high - c[i].high) }; ++ it;        }        ++ it;    }    if ((++ it) != s.end()) {        t[++ add] = (temp) { it -> pos, abs(it -> high - c[i].high) };        if ((++ it) != s.end()) t[++ add] = (temp) { it -> pos, abs(it -> high - c[i].high) };    }        sort(t + 1, t + add + 1);    nextb[i] = t[1].pos; if (add == 1) return; nexta[i] = t[2].pos;}inline void Query(int St, int X, long long &ta, long long &tb){    for (int i = 19; ~i; -- i) if (f[St][i] && fa[St][i] + fb[St][i] <= X) {        ta += fa[St][i]; tb += fb[St][i];        X -= fa[St][i] + fb[St][i]; St = f[St][i];    }    int posa = nexta[St]; if (!posa) return;    int dis = abs(c[posa].high - c[St].high); if (dis <= X) ta += dis;}int main(){    ios :: sync_with_stdio(false);    cin >> N;    for (int i = 1; i <= N; ++ i) {        cin >> c[i].high; c[i].pos = i;    }        for (int i = N; i; -- i) {        s.insert(c[i]); if (i ^ N) Find(i);    }    for (int i = 1; i <= N; ++ i) {        int pos1 = nexta[i], pos2 = nextb[nexta[i]];        fa[i][0] = pos1 ? abs(c[pos1].high - c[i].high) : 0;        fb[i][0] = pos2 ? abs(c[pos2].high - c[pos1].high) : 0;        f[i][0] = pos2;    }    for (int j = 1; j < 20; ++ j) {        for (int i = 1; i <= N; ++ i) {            f[i][j] = f[f[i][j - 1]][j - 1];            fa[i][j] = fa[i][j - 1] + fa[f[i][j - 1]][j - 1];            fb[i][j] = fb[i][j - 1] + fb[f[i][j - 1]][j - 1];        }    }        cin >> x0; int ans = 0;    long long ansa = 1e15, ansb = 0ll;    for (int i = 1; i <= N; ++ i) {        long long ta = 0ll, tb = 0ll; Query(i, x0, ta, tb);        if (tb && (!ans || ansa * tb > ansb * ta)) {            ansa = ta; ansb = tb; ans = i;        }    }    cout << ans << endl;        for (cin >> M; M --; ) {        cin >> S >> x1;        long long ta = 0ll, tb = 0ll; Query(S, x1, ta, tb);        cout << ta << " " << tb << endl;    }            return 0;}




2 0