THUWC2017 T1
考场上的心路历程
因为当时还不会泰勒展开,拉格朗日余项,拉格朗日中值定理和导数(本来我预习了的,但是考试的时候不记得导数的符号了,导致没有看懂给出的提示),所以只好打了一个LCT维护联通性,打算骗分。
但是因为基本功不扎实,LCT并写不对。
回来之后深刻反省,苦练LCT,终于一个小时1A此题。
时间限制: 5.0 秒
内存限制: 512 MB
相关文件: 下载目录
【问题背景】
数字和数学规律主宰着这个世界。
机器的运转,
生命的消长,
宇宙的进程,
这些神秘而又美妙的过程无不可以用数学的语言展现出来。
这印证了一句古老的名言:
“学好数理化,走遍天下都不怕。”
【问题描述】
学渣小R被大学的数学课程虐得生活不能自理,微积分的成绩曾是他在教室里上的课的最低分。然而他的某位陈姓室友却能轻松地在数学考试中得到满分。为了提升自己的数学课成绩,有一天晚上(在他睡觉的时候),他来到了数学王国。
数学王国中,每个人的智商可以用一个属于
[0,1]
的实数表示。数学王国中有
n
个城市,编号从
- 正弦函数
sin(ax+b) (a∈[0,1],b∈[0,π],a+b∈[0,π]) - 指数函数 eax+b (a∈[−1,1],b∈[−2,0],a+b∈[−2,0])
- 一次函数 ax+b (a∈[−1,1],b∈[0,1],a+b∈[0,1])
数学王国中的魔法桥会发生变化,有时会有一座魔法桥消失,有时会有一座魔法桥出现。但在任意时刻,只存在至多一条连接任意两个城市的简单路径(即所有城市形成一个森林)。在初始情况下,数学王国中不存在任何的魔法桥。
数学王国的国王拉格朗日很乐意传授小R数学知识,但前提是小R要先回答国王的问题。这些问题具有相同的形式,即一个智商为 x 的人从城市
u 旅行到城市 v (即经过u 到 v 这条路径上的所有城市,包括u 和 v )且做了所有城市内的数学题后,他所有得分的总和是多少。【输入格式】
从标准输入读入数据。
第一行两个正整数
n,m 和一个字符串 type 。表示数学王国中共有 n 座城市,发生了m 个事件,该数据的类型为 type 。 type 字符串是为了能让大家更方便地获得部分分,你可能不需要用到这个输入。其具体含义在【限制与约定】中有解释。接下来 n 行,第
i 行表示初始情况下编号为 i 的城市的魔法球中的函数。一个魔法用一个整数f 表示函数的类型,两个实数 a,b 表示函数的参数,若- f=1 ,则函数为 f(x)=sin(ax+b)(a∈[0,1],b∈[0,π],a+b∈[0,π])
- f=2 ,则函数为 f(x)=eax+b(a∈[−1,1],b∈[−2,0],a+b∈[−2,0])
- f=3 ,则函数为 f(x)=ax+b(a∈[−1,1],b∈[0,1],a+b∈[0,1])
接下来 m 行,每行描述一个事件,事件分为四类。
appear u v
表示数学王国中出现了一条连接u 和 v 这两座城市的魔法桥(0≤u,v<n,u≠v) ,保证连接前 u 和v 这两座城市不能互相到达。disappear u v
表示数学王国中连接 u 和v 这两座城市的魔法桥消失了,保证这座魔法桥是存在的。magic c f a b
表示城市 c 的魔法球中的魔法变成了类型为f ,参数为 a,b 的函数travel u v x
表示询问一个智商为 x 的人从城市u 旅行到城市 v (即经过u 到 v 这条路径上的所有城市,包括u 和 v )后,他得分的总和是多少。若无法从u 到达 v ,则输出一行一个字符串unreachable
。
【输出格式】
输出到标准输出。
对于每个询问,输出一行实数,表示得分的总和。
【样例1】
输入
3 7 C1 1 1 0 3 0.5 0.5 3 -0.5 0.7 appear 0 1 travel 0 1 0.3 appear 0 2 travel 1 2 0.5 disappear 0 1 appear 1 2 travel 1 2 0.5
输出
9.45520207e-001 1.67942554e+000 1.20000000e+000
【限制与约定】
对于100%的数据,
1≤n≤100000,1≤m≤200000 。本题共有20个数据点,每个数据点5分。
【评分标准】
如果你的答案与标准答案的相对误差在 10−7 以内或绝对误差在 10−7 以内,则被判定为正确。
如果你的所有答案均为正确,则得满分,否则得0分。
请注意输出格式:每行输出一个答案,答案只能为
unreachable
或者一个实数(建议使用科学计数法表示)。每行的长度不得超过50。错误输出格式会被判定为0分。【小R教你学数学】
若函数 f(x) 的 n 阶导数在
[a,b] 区间内连续,则对 f(x) 在 x0(x0∈[a,b]) 处使用 n 次拉格朗日中值定理可以得到带拉格朗日余项的泰勒展开式f(x)=f(x0)+f′(x0)(x−x0)1!+f″(x0)(x−x0)22!+⋯+f(n−1)(x0)(x−x0)n−1(n−1)!+f(n)(ξ)(x−x0)nn!,x∈[a,b] 其中,当 x>x0 时, ξ∈[x0,x] 。当 x<x0 时, ξ∈[x,x0] 。
f(n) 表示函数 f 的
n 阶导数
Code
#include <bits/stdc++.h> const int MAXS = 20; int n, m; char type[MAXS]; int u, v, c, f; double x, a, b; template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; char f = 1; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= f; } namespace T { const int MAXN = 100010; const int MAXB = 30; int sz, fat[MAXN]; struct Node { int num; bool isa; Node *fa, *ch[2]; double data[MAXB + 1], sum[MAXB + 1]; void pushdown(); void update(); void splay(); void rotate(); void access(); void be_rot(); bool is_rot(); int find_rot(); }; Node *nul = new Node, *to[MAXN]; bool Node::is_rot() {return fa == nul || fa -> ch[0] != this && fa -> ch[1] != this;} void Node::rotate() { Node *pa = fa; fa = pa -> fa; if (!pa -> is_rot()) { bool t = (fa -> ch[0] == pa ? 0 : 1); fa -> ch[t] = this; } bool t = (pa -> ch[0] == this ? 0 : 1); pa -> fa = this; pa -> ch[t] = ch[t^1]; if (ch[t^1] != nul) ch[t^1] -> fa = pa; ch[t^1] = pa; pa -> update(); update(); } void Node::access() { Node *x = this; x -> splay(); x -> pushdown(); x -> ch[1] = nul; x -> update(); while (x -> fa != nul) { Node *e = x -> fa; e -> splay(); e -> pushdown(); e -> ch[1] = x; e -> update(); x = e; } } void Node::splay() { sz = 0; Node *tmp = this; while (!tmp -> is_rot()) { fat[++sz] = tmp -> num; tmp = tmp -> fa; } fat[++sz] = tmp -> num; for (int i = sz; i >= 1; i--) to[fat[i]] -> pushdown(); while (!is_rot()) { if (fa -> is_rot()) rotate(); else { bool t = (fa -> fa -> ch[0] == fa ? 0 : 1); if (fa -> ch[t] == this) fa -> rotate(), rotate(); else rotate(), rotate(); } } } void Node::pushdown() { if (!isa) return; isa = false; Node *tmp = ch[0]; ch[0] = ch[1]; ch[1] = tmp; if (ch[0] != nul) ch[0] -> isa ^= 1; if (ch[1] != nul) ch[1] -> isa ^= 1; } int Node::find_rot() { access(); splay(); Node *tmp = this; pushdown(); while (tmp -> ch[0] != nul) { tmp = tmp -> ch[0]; tmp -> pushdown(); } return tmp -> num; } void Node::be_rot() { access(); splay(); isa ^= 1; } void Node::update() { memset(sum, 0, sizeof sum); for (int i = 0; i <= MAXB; i++) sum[i] += data[i]; if (ch[0] != nul) for (int i = 0; i <= MAXB; i++) sum[i] += ch[0] -> sum[i]; if (ch[1] != nul) for (int i = 0; i <= MAXB; i++) sum[i] += ch[1] -> sum[i]; } void main() { nul -> isa = false; nul -> num = 0; nul -> fa = nul -> ch[0] = nul -> ch[1] = nul; for (int i = 0; i <= MAXB; i++) nul -> data[i] = nul -> sum[i] = 0; } void get_sin(int now, double x, double y) { double jie = 1, f = -1, ci = 1; for (int i = 0; i <= MAXB; i++) { if (i) jie *= i; if (!(i & 1)) { f = -f; to[now] -> data[i] = sin(y); } else to[now] -> data[i] = cos(y); to[now] -> data[i] *= f * ci; to[now] -> data[i] /= jie; ci *= x; } } void get_exp(int now, double x, double y) { double jie = 1, ci = 1; for (int i = 0; i <= MAXB; i++) { if (i) jie = jie * i; to[now] -> data[i] = ci * exp(y) / jie; ci = ci * x; } } void get_xia(int now, double x, double y) { to[now] -> data[0] = y; to[now] -> data[1] = x; for (int i = 2; i <= MAXB; i++) to[now] -> data[i] = 0; } void build(int now, int tp, double x, double y) { to[now] = new Node; to[now] -> num = now; to[now] -> isa = false; to[now] -> fa = to[now] -> ch[0] = to[now] -> ch[1] = nul; if (tp == 1) get_sin(now, x, y); else if (tp == 2) get_exp(now, x, y); else get_xia(now, x, y); to[now] -> update(); } void link(int x, int y) { to[x] -> be_rot(); to[x] -> splay(); to[y] -> access(); to[y] -> splay(); to[x] -> fa = to[y]; } void del(int x, int y) { to[x] -> be_rot(); to[y] -> access(); to[y] -> splay(); to[y] -> pushdown(); to[y] -> ch[0] = nul; to[x] -> fa = nul; to[y] -> update(); } void magic(int c, int f, double x, double y) { to[c] -> splay(); if (f == 1) get_sin(c, x, y); else if (f == 2) get_exp(c, x, y); else get_xia(c, x, y); to[c] -> update(); } void query(int u, int v, double x) { double ans = 0; if (to[u] -> find_rot() != to[v] -> find_rot()) { puts("unreachable"); return; } to[u] -> be_rot(); to[v] -> access(); to[v] -> splay(); double tmp = 1; for (int i = 0; i <= MAXB; i++) { ans += tmp * to[v] -> sum[i]; tmp *= x; } printf("%.10lf\n", ans); } } int main() { #ifndef __LOCAL_TEST freopen("math.in", "r", stdin); freopen("math.out", "w", stdout); #endif T::main(); in(n); in(m); scanf("%*s"); for (int i = 1; i <= n; i++) { in(f); scanf("%lf%lf", &a, &b); T::build(i, f, a, b); } while (m--) { scanf("%s", type); if (type[0] == 'a') {in(u); in(v); u++; v++; T::link(u, v);} else if (type[0] == 'd') {in(u); in(v); u++; v++; T::del(u, v);} else if (type[0] == 'm') {in(c); in(f); c++; scanf("%lf%lf", &a, &b); T::magic(c, f, a, b);} else {in(u); in(v); u++; v++; scanf("%lf", &x); T::query(u, v, x);} } return 0; }