【LOJ】#2289. 「THUWC 2017」在美妙的数学王国中畅游

题解

我们发现,题目告诉我们这个东西就是一个lct

首先,如果只有3,问题就非常简单了,我们算出所有a的总和,所有b的总和就好了

要是1和2也是多项式就好了……其实可以!也就是下面泰勒展开的用处,我们可以用一个多项式取逼近这个函数,而且,多项式次数越高越准确,我们大概到13次多项式就好了

如何创造出这个多项式呢,泰勒展开的式子是这样的
\(\sum_{i = 0}^{n} \frac{f^{(i)}(x_{0}) (x - x_{0})^{i}}{i!}\)
其中\(f^{(i)}(x)\)表示\(f(x)\)\(i\)阶导数

然后问题就变成了维护13个值的和的lct了

然后,如何求导
根据高中选修2-2
我们有
\(f(g(x)) = g'(x)f'(g(x))\)
对于第一类型的函数
\(sin^{(1)}(ax + b) = a\cdot cos(ax + b)\)
\(sin^{(2)}(ax + b) = -a^{2}\cdot sin(ax + b)\)
\(sin^{(3)}(ax + b) = -a^{3}\cdot cos(ax + b)\)
\(sin^{(4)}(ax + b) = a^{4}\cdot sin(ax + b)\)
4次一个轮回

对于第二类型的函数
\(f(x)^{(1)} = a\cdot e^{ax + b}\)
\(f(x)^{(2)} = a^{2}\cdot e^{ax + b}\)
\(f(x)^{(n)} = a^{n}\cdot e^{ax + b}\)

= =lct的cut是,先把一个点变成根,另一个点Access一下,再Splay成根,然后断掉根节点的左儿子

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
//#define ivorysi
#define pb push_back
#define MAXN 100005
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long int64;
typedef double db;
int N,M;
char s[25];
db fac[20];
struct Tr {
    Tr *lc,*rc,*fa;
    db sum[14],f[14];
    bool rev;
    void Update() {
	for(int i = 0 ; i <= 13 ; ++i) sum[i] = f[i];
	if(lc) for(int i = 0 ; i <= 13 ; ++i) sum[i] += lc->sum[i];
	if(rc) for(int i = 0 ; i <= 13 ; ++i) sum[i] += rc->sum[i];
    }
    void Reverse() {
	rev ^= 1;swap(lc,rc);
    }
    void Pushdown() {
	if(rev) {
	    if(lc) lc->Reverse();
	    if(rc) rc->Reverse();
	    rev = 0;
	}
    }
}*tr[MAXN];
bool which(Tr *u) {
    return u == u->fa->rc;
}
bool isRoot(Tr *u) {
    if(!u->fa) return 1;
    return u->fa->rc != u && u->fa->lc != u;
}
void Rotate(Tr *u) {
    Tr *v = u->fa,*w = v->fa;
    Tr *b = u == v->lc ? u->rc : u->lc;
    if(!isRoot(v)) (v == w->lc ? w->lc : w->rc) = u;
    u->fa = w;v->fa = u;
    if(b) b->fa = v;
    if(u == v->lc) v->lc = b,u->rc = v;
    else v->rc = b,u->lc = v;
    v->Update();
}
void Splay(Tr *u) {
    static Tr* que[MAXN];
    int tot = 0;Tr *x;
    for(x = u ; !isRoot(x) ; x = x->fa) que[++tot] = x;
    que[++tot] = x;
    for(int i = tot ; i >= 1 ; --i) que[i]->Pushdown();
    while(!isRoot(u)) {
	if(!isRoot(u->fa)) {
	    if(which(u->fa) == which(u)) Rotate(u->fa);
	    else Rotate(u);
	}
	Rotate(u);
    }
    u->Update();
}
void Access(Tr *u) {
    for(Tr *x = NULL ; u ; x = u, u = u->fa) {
	Splay(u);
	u->rc = x;
	u->Update();
    }
}
Tr* FindRoot(Tr *u){
    Access(u);Splay(u);
    Tr *res = u;
    res->Pushdown();
    while(res->lc) {res = res->lc;res->Pushdown();}
    return res;
}
void MakeRoot(Tr *u) {Access(u);Splay(u);u->Reverse();}
void Link(Tr *u,Tr *v) {MakeRoot(u);u->fa = v;}
void Cut(Tr *u,Tr *v) {MakeRoot(u);Access(v);Splay(v);v->lc = u->fa = 0;v->Update();}
db Select(Tr *u,Tr *v,db x) {
    MakeRoot(u);Access(v);Splay(u);
    db res = 0,t = 1;
    for(int i = 0 ; i <= 13 ; ++i) {
	res += t * u->sum[i];
	t *= x;
    }
    return res;
}
void Change(Tr *u,int ty,db a,db b) {
    MakeRoot(u);
    memset(u->f,0,sizeof(u->f));
    if(ty == 1) {
	db x = 1;
	for(int i = 0 ; i <= 13 ; ++i) {
	    if(i % 4 == 0) u->f[i] = x * sin(b) / fac[i];
	    if(i % 4 == 1) u->f[i] = x * cos(b) / fac[i];
	    if(i % 4 == 2) u->f[i] = -x * sin(b) / fac[i];
	    if(i % 4 == 3) u->f[i] = -x * cos(b) / fac[i];
	    x *= a;
	}
    }
    else if(ty == 2) {
	db v = exp(b),x = 1;
	for(int i = 0 ; i <= 13 ; ++i) {u->f[i] = v * x / fac[i];x *= a;}
    }
    else {
	u->f[1] = a;u->f[0] = b;
    }
    u->Update();
}
void Solve() {
    scanf("%d%d",&N,&M);
    scanf("%s",s + 1);
    fac[0] = 1;
    for(int i = 1 ; i <= 13 ; ++i) fac[i] = fac[i - 1] * i;
    int f,u,v;db a,b;
    for(int i = 1 ; i <= N ; ++i) {
	tr[i] = new Tr;tr[i]->lc = tr[i]->rc = tr[i]->fa = 0;
	scanf("%d%lf%lf",&f,&a,&b);
	Change(tr[i],f,a,b);
    }
    for(int i = 1 ; i <= M ; ++i) {
	scanf("%s",s + 1);
	if(s[1] == 'a' || s[1] == 'd') {
	    scanf("%d%d",&u,&v);++u;++v;
	    if(s[1] == 'a') Link(tr[u],tr[v]);
	    if(s[1] == 'd') Cut(tr[u],tr[v]);
	}
	else if(s[1] == 'm') {
	    scanf("%d%d%lf%lf",&u,&f,&a,&b);++u;
	    Change(tr[u],f,a,b);
	}
	else {
	    scanf("%d%d%lf",&u,&v,&a);++u;++v;
	    if(FindRoot(tr[u]) != FindRoot(tr[v])) puts("unreachable");
	    else printf("%.8e\n",Select(tr[u],tr[v],a));
	}
    }
}

int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}
posted @ 2018-05-23 15:38  sigongzi  阅读(172)  评论(0编辑  收藏  举报