WC模拟(12.20) T1 在美妙的数学王国中畅游(bzoj5020)

在美妙的数学王国中畅游

题目背景:

12.20 WC模拟T1 (bzoj5020)

分析:LCT + 泰勒展开

 

题目直接给出了泰勒展开公式,显然就是让你把三个函数直接展开,我们可以直接代入一个固定的x0,然后求出f(x0)之和,需要乘(x - x0)的和,乘(x - x0)2的和······考虑到数量级的减小是非常快的,那么我们只用考虑前面的有限项就可以了,一般保留11 ~ 15项就能保证精度了。至于n阶导,对于sin(ax + b)n阶导数为,a * cos(ax + b), -a2 * sin(ax + b)-a3 *cos(ax + b) ……eax + b的导数为a * eax + b,a2 * eax + b, a3 * eax + b ……所以最终实现为用link_cut_tree维护森林,在节点上维护泰勒展开项,修改或者改变形态直接合并更新信息即可。

Source:

/*
	created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <iomanip>  

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

/*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = read(), iosig = false; !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;	
	}
	for (x = 0; isdigit(c); c = read()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}


template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

///*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
		if (c == '-') iosig = true;	
	for (x = 0; isdigit(c); c = getchar()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int MAXN = 100000 + 10;
const int max = 11;

int type;
double js[max];
char s[15];

struct data {
	double sum[max];
	inline data operator + (const data &a) const {
		data temp;
		for (int i = 0; i < max; ++i) temp.sum[i] = a.sum[i] + sum[i];
		return temp ;
	}
} ;

struct node *null;

struct node {
	node *c[2], *fa, *pa;
	bool rev;
	data val, sum;
	
	node() {}
	node(data val) : fa(null), pa(null), rev(false), val(val), sum(val) {
		c[0] = c[1] = null;
	}
	
	inline void maintain() {
		if (this == null) return ;
		sum = c[0]->sum + c[1]->sum + val;
	}
	
	inline int relation() {
		return this == fa->c[1];
	}
	
	inline void reverse() {
		if (this == null) return ;
		std::swap(c[0], c[1]), rev ^= 1;	
	}
	
	inline void push_down() {
		if (this == null) return ;
		if (rev) c[0]->reverse(), c[1]->reverse(), rev ^= 1;
	}
	
	inline void rotate() {
		push_down();
		node *old_fa = fa;
		int x = relation();
		pa = fa->pa, fa->pa = null;
		if (old_fa->fa != null) old_fa->fa->c[old_fa->relation()] = this;
		fa = old_fa->fa, old_fa->c[x] = c[x ^ 1];
		if (c[x ^ 1] != null) c[x ^ 1]->fa = old_fa;
		c[x ^ 1] = old_fa, old_fa->fa = this, old_fa->maintain(), maintain();
	}
	
	inline void splay(node *target = null) {
		while (fa != target) {
			fa->fa->push_down(), fa->push_down();
			if (fa->fa == target) rotate();
			else if (fa->relation() == relation()) fa->rotate(), rotate();
			else rotate(), rotate();
		}
		push_down();
	}
	
	inline void expose() {
		splay();
		if (c[1] != null) 
			c[1]->fa = null, c[1]->pa = this, c[1] = null, maintain();
	}
	
	inline bool splice() {
		splay();
		if (pa != null) {
			pa->expose(), pa->c[1] = this, fa = pa, pa = null, fa->maintain();
			return true;
		} else return false;
	}
	
	inline void access() {
		expose();
		while (splice());
		splay();
	}
	
	inline void evert() {
		access(), reverse();
	}
} point[MAXN];

inline data set_type(int type, double a, double b) {
	data temp;
	for (int i = 0; i < max; ++i) temp.sum[i] = 0;
	switch (type) {
		case 1: {
			double sin_b = std::sin(b), cos_b = std::cos(b);
			double a_mul = 1, sign = 1;
			for (int j = 0; j < max; j += 2, sign = -sign) {
				temp.sum[j] = sign * a_mul * sin_b / js[j];
				a_mul *= a, a_mul *= a;
			}
			a_mul = a, sign = 1;
			for (int j = 1; j < max; j += 2, sign = -sign) {
				temp.sum[j] = sign * a_mul * cos_b / js[j];
				a_mul *= a, a_mul *= a; 
			}
			break ;
		}
		case 2: {
			double e_b = std::exp(b), a_mul = 1;
			for (int j = 0; j < max; ++j) 
				temp.sum[j] = a_mul * e_b / js[j], a_mul *= a;
			break ;
		}
		case 3: temp.sum[0] = b, temp.sum[1] = a;
				break ;
	}
	return temp;
}

inline void dfs(node *u) {
	if (u->c[0] != null) dfs(u->c[0]);
	std::cerr << u - point << ' ';
	if (u->c[1] != null) dfs(u->c[1]);
}

inline void link(node *u, node *v) {
	u->evert(), u->pa = v;
}

inline void cut(node *u, node *v) {
	u->evert(), v->access(), v->c[0] = null, u->fa = null, v->maintain();
}

inline void modify(node *u, int type, double a, double b) {
	u->evert(), u->val = set_type(type, a, b), u->maintain();
}

inline data query(node *u, node *v) {
	return u->evert(), v->access(), v->sum;
}

inline node *find_root(node *u) {
	u->access();
	for (; u->c[0] != null; u->push_down(), u = u->c[0]);
	return u->splay(), u;
}

inline void calc(double a, data cur) {
	double x = 1, ans = 0;
	for (int i = 0; i < max; ++i, x = x * a) ans += cur.sum[i] * x;
	printf("%0.9lf\n", ans);
}

int n, m, x, y;
double a, b;
inline void read_in() {
	null = &point[0], null->c[0] = null->c[1] = null->fa = null->pa = null;
	null->rev = false, js[0] = 1;
	for (int i = 0; i < max; ++i) null->sum.sum[i] = null->val.sum[i] = 0;
	for (int i = 1; i < max; ++i) js[i] = js[i - 1] * (double)i;
	R(n), R(m), scanf("%s", s);
	for (int i = 1; i <= n; ++i) {
		R(type), scanf("%lf%lf", &a, &b);
		point[i] = node(set_type(type, a, b));
	}
}

inline void solve() {
	for (int i = 1; i <= m; ++i) {
		scanf("%s", s);
		switch (s[0]) {
			case 'a': R(x), R(y), ++x, ++y, link(&point[x], &point[y]);
					  break ;
			case 'd': R(x), R(y), ++x, ++y, cut(&point[x], &point[y]);
					  break ;
			case 'm': R(x), R(y), scanf("%lf%lf", &a, &b), ++x;
					  modify(&point[x], y, a, b);
					  break ;
			case 't': R(x), R(y), scanf("%lf", &a), ++x, ++y;
					  if (find_root(&point[x]) != find_root(&point[y])) {
					  	printf("unreachable\n");
					  } else calc(a, query(&point[x], &point[y]));
					  break ;
		}
	}
}

int main() {
	read_in();
	solve();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值