NOIP 2012 Day1 T3 - set + 树上倍增

来源:互联网 发布:七妹电音软件 编辑:程序博客网 时间:2024/06/10 07:37

这道题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;}



0 0