【CodeVS 1199】【NOIP 2012】开车旅行

http://codevs.cn/problem/1199/

主要思想是倍增,对于第一个回答从后往前扫,依次插入平衡树中。

我写的splay,比较繁琐。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100003;
int in() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < ‘0‘ || c > ‘9‘; c = getchar())
		if (c == ‘-‘) fh = -1;
	for(; c >= ‘0‘ && c <= ‘9‘; c = getchar())
		k = (k << 3) + (k << 1) + c - ‘0‘;
	return k * fh;
}

int h[N], n, m, nxt_a[N], nxt_b[N], f[N][18], sum_a[N][18], sum_b[N][18];

struct Splay {
	struct node {
		node *ch[2], *fa;
		int id, num;
		bool pl() {return fa->ch[1] == this;}
		void setc(node *r, bool c) {ch[c] = r; r->fa = this;}
	} *root, *null;
	void init() {
		null = new node;
		null->id = null->num = 0;
		null->ch[0] = null->ch[1] = null->fa = null;
		root = null;
	}
	void printall(node *r) {
		if (r == null) return;
		printall(r->ch[0]);
		printf("%d ", r->num);
		printall(r->ch[1]);
	}
	void rotate(node *r) {
		node *f = r->fa;
		bool c = r->pl();
		if (f != root) f->fa->setc(r, f->pl());
		else root = r, r->fa = null;
		f->setc(r->ch[!c], c);
		r->setc(f, !c);
	}
	void splay(node *r) {
		for(; r->fa != null; rotate(r))
			if (r->fa->fa != null) rotate(r->fa->pl() == r->pl() ? r->fa : r);
	}
	struct data {
		int del, h, id;
		bool operator < (const data &A) const {
			return (del == A.del ? h < A.h : del < A.del);
		}
	} a[5];
	node *getl(int num, int to) {
		node *r = root->ch[0];
		if (r == null) {a[to] = (data) {0x7fffffff, 0, 0}; return r;}
		while (r->ch[1] != null) r = r->ch[1];
		a[to] = (data) {abs(num - r->num), r->num, r->id};
		return r;
	}
	node *getr(int num, int to) {
		node *r = root->ch[1];
		if (r == null) {a[to] = (data) {0x7fffffff, 0, 0}; return r;}
		while (r->ch[0] != null) r = r->ch[0];
		a[to] = (data) {abs(num - r->num), r->num, r->id};
		return r;
	}
	void mk_nxt(int &back_1, int &back_2, int id, int num) {
		node *r = root;
		if (r == null) {
			root = new node;
			root->id = id; root->num = num;
			root->ch[0] = root->ch[1] = root->fa = null;
			back_1 = back_2 = 0;
			return;
		}
		bool c;
		while (true) {
			if (r->num > num) c = 0;
			else c = 1;
			if (r->ch[c] == null) {
				r->ch[c] = new node;
				r->ch[c]->fa = r;
				r = r->ch[c];
				r->id = id; r->num = num;
				r->ch[0] = r->ch[1] = null;
				splay(r);
				node *ll = getl(num, 0), *rr = getr(num, 1);
				if (ll != null) {splay(ll); getl(num, 2);} else a[2] = (data) {0x7fffffff, 0, 0};
				if (rr != null) {splay(rr); getr(num, 3);} else a[3] = (data) {0x7fffffff, 0, 0};
				sort(a, a + 4);
				if (a[1].id != 0) {
					back_1 = a[1].id; back_2 = a[0].id;
				} else if (a[0].id != 0) {
					back_1 = 0; back_2 = a[0].id;
				} else {
					back_1 = 0; back_2 = 0;
				}
				return;
			} else r = r->ch[c];
		}
	}
} T;

void cal(int &a, int &b, int s, int x) {
	a = b = 0;
	for(int i = 17; i >= 0; --i)
		if (f[s][i] && sum_a[s][i] + sum_b[s][i] <= x) {
			a += sum_a[s][i]; b += sum_b[s][i];
			x -= sum_a[s][i]; x -= sum_b[s][i];
			s = f[s][i];
		}
	if (sum_a[s][0] <= x && nxt_a[s])
		a += sum_a[s][0];
}

int main() {
	T.init();
	n = in();
	for(int i = 1; i <= n; ++i) h[i] = in();
	for(int i = n; i >= 1; --i)	T.mk_nxt(nxt_a[i], nxt_b[i], i, h[i]);

	for(int i = 1; i <= n; ++i) {
		if (nxt_a[i]) sum_a[i][0] = abs(h[nxt_a[i]] - h[i]);
		if (nxt_b[nxt_a[i]]) {
			sum_b[i][0] = abs(h[nxt_b[nxt_a[i]]] - h[nxt_a[i]]);
			f[i][0] = nxt_b[nxt_a[i]];
		}
	}
	for(int j = 1; j <= 17; ++j)
		for(int i = 1; i <= n; ++i)
			if (f[f[i][j - 1]][j - 1]) {
				f[i][j] = f[f[i][j - 1]][j - 1];
				sum_a[i][j] = sum_a[i][j - 1] + sum_a[f[i][j - 1]][j - 1];
				sum_b[i][j] = sum_b[i][j - 1] + sum_b[f[i][j - 1]][j - 1];
			}

	int a, b, s, x, ans = 0; double ans_num = -1.0, now;
	x = in();
	for(int i = 1; i <= n; ++i) {
		cal(a, b, i, x);
		if (b != 0) now = 1.0 * a / b;
		else now = -1.0;
		if (ans_num == -1.0 || (ans_num != -1.0 && now != -1.0 && now <= ans_num))
			if (fabs(ans_num - now) < 1e-12) {
				if (h[i] > h[ans]) ans = i;
			} else ans_num = now, ans = i;
	}
	printf("%d\n", ans);

	m = in(); int i = 0;
	while (m--) {
		++i;
		s = in(); x = in();
		cal(a, b, s, x);
		printf("%d %d\n", a, b);
	}

	return 0;
}

_(:з」∠)_

时间: 2024-12-18 07:59:36

【CodeVS 1199】【NOIP 2012】开车旅行的相关文章

noip 2012 开车旅行

/*考场上写的暴力 40分钟70分*/ #include<iostream> #include<cstdio> #include<cstring> #define base 1000000000 #define maxn 100010 #define ll long long using namespace std; ll n,m,h[maxn],X,A[maxn],B[maxn],st,ans; bool falg; double mii=base; ll init(

codevs 1199 开车旅行 2012年NOIP全国联赛提高组

1199 开车旅行 2012年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i, j] = |Hi − Hj|. 旅行过程中,小A 和小B轮流开

noip2012 开车旅行

P1081 开车旅行 139通过 484提交 题目提供者洛谷OnlineJudge 标签倍增2012NOIp提高组 难度提高+/省选- 提交该题 讨论 题解 记录 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi− Hj|. 旅行过程中,小

[NOIP2012] 提高组 洛谷P1081 开车旅行

题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi− Hj|. 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次.他们计划 选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行.小 A 和小 B

NOIP 2012 题解

[D1T1vigenere密码] P1778vigenere密码 Accepted 标签:[显示标签] 描述 16世纪法国外交家Blaise de Vigenère设计了一种多表密码加密算法--Vigenère密码.Vigenère密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为南军所广泛使用. 在密码学中,我们称需要加密的信息为明文,用M表示:称加密后的信息为密文,用C表示:而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,记为k. 在Vigenère

开车旅行

洛谷P1081 开车旅行  NOIP 2012 提高组 第一天 第三题 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi− Hj|. 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次.他们计划 选择一个城市 S 作

【NOIP2012】开车旅行

题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi? Hj|. 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次.他们计划 选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行.小 A 和小 B

洛谷P1081 开车旅行

P1081 开车旅行 152通过 524提交 题目提供者洛谷OnlineJudge 标签倍增NOIp提高组2012 难度省选/NOI- 提交该题 讨论 题解 记录 最新讨论 我前排提醒一下 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi−

习题:开车旅行(倍增+预处理)

开车旅行(NOIP提高组2012) [描述]小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i 的海拔高度为Hi,城市i 和城市j 之间的距离d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i,j] = |Hi - Hj|.旅行过程中,小A和小B轮流开车,第一天小A开车,之后每天轮换一次.他们计划选择一个城市S作为起点,一直向东行驶,并且最多行驶X公里就结束旅行.小A和小B的驾驶风格不同,小B总是

NOIP 2012

Prob.1 vigenere密码 模拟代码: #include<cstdio> #include<cstring> #include<iostream> using namespace std; char K[105],A[1005]; int main(){ scanf("%s",K);int p=0; scanf("%s",A); for(int i=0;A[i];i++){ char k=K[p]; if(isupper(