这道题NOIP之前没码完。。身败名裂。。
很明显的树上倍增啦。。但有一个问题是如何快速获得每个点的两个最近和次远。。
用set。。
完了。。
细节见代码。。
// NOIP2012 Day1 T3
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=100000+5, LOG=21, INF=0x3f3f3f3f;
#define rep(i,a,b) for (int i=a; i<=b; i++)
#define dep(i,a,b) for (int i=a; i>=b; i--)
#define read(x) scanf("%d", &x)
#define fill(a,x) memset(a, x, sizeof(a))
struct Node {
int h, id;
bool operator < (const Node x) const { return h<x.h; }
}c[N];
set<Node> S;
int n, m, s, x, x0, ans, nextt[N][2], dist[N][2], g[N][LOG];
LL f[N][LOG][2], a, b;
void update(Node x, Node y) { // 更新树边,0为最近点,1为次近点
if (!nextt[x.id][0]) {
nextt[x.id][0]=y.id;
dist[x.id][0]=abs(x.h-y.h);
}
else if (abs(x.h-y.h)<dist[x.id][0] || (abs(x.h-y.h)==dist[x.id][0] && y.h<c[nextt[x.id][0]].h)) {
nextt[x.id][1]=nextt[x.id][0];
dist[x.id][1]=dist[x.id][0];
nextt[x.id][0]=y.id;
dist[x.id][0]=abs(x.h-y.h);
}
else if (!nextt[x.id][1] || abs(x.h-y.h)<dist[x.id][1] || (abs(x.h-y.h)==dist[x.id][1] && y.h<c[nextt[x.id][1]].h)) {
nextt[x.id][1]=y.id;
dist[x.id][1]=abs(x.h-y.h);
}
}
/*
令
g[i][j]为从i点走2^j个轮回后的位置,
f[i][j][0]为从i点走2^j个轮回后A走过的距离,
f[i][j][1]为从i点走2^j个轮回后B走过的距离。
*/
void init_tree() {
rep(i,1,n) {
g[i][0]=nextt[nextt[i][1]][0];
f[i][0][0]=dist[i][1];
f[i][0][1]=dist[nextt[i][1]][0];
}
rep(j,1,20)
rep(i,1,n) {
g[i][j]=g[g[i][j-1]][j-1];
f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];
f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];
}
}
void query(int s, int x, LL &da, LL &db) {
// 从城市s出发,最多走x距离,A、B分别开车的距离da、db
dep(i,20,0) if (f[s][i][0]+f[s][i][1]<=x && g[s][i]) {
da+=f[s][i][0];
db+=f[s][i][1];
x-=(f[s][i][0]+f[s][i][1]);
s=g[s][i];
}
if (nextt[s][1] && dist[s][1]<=x) da+=dist[s][1];
// 注意A可能还可以开一次
}
int main()
{
read(n);
rep(i,1,n) {
read(c[i].h);
c[i].id=i;
}
set<Node>::iterator it;
dep(i,n,1) { // 按编号从大到小顺序建树
S.insert(c[i]);
it=S.find(c[i]);
// 找到c[i]的位置,并取出离它最近、次近的城市
if (it!=S.begin()) {
it--;
update(c[i], *it);
if (it!=S.begin()) {
it--;
update(c[i], *it);
it++;
}
it++;
}
if ((++it)!=S.end()) {
update(c[i], *it);
if ((++it)!=S.end()) update(c[i], *it);
it--;
}
it--;
}
init_tree();
read(x0);
a=1e+15, b=0;
rep(i,1,n) { // 对于第一问,枚举答案
LL da=0, db=0;
query(i, x0, da, db);
if (db && (ans==0 || a*db>b*da)) ans=i, a=da, b=db;
}
printf("%d\n", ans);
read(m);
rep(i,1,m) {
read(s); read(x);
LL da=0, db=0;
query(s, x, da, db);
printf("%I64d %I64d\n", da, db);
}
return 0;
}