[THUWC2017][bzoj5020] 在美妙的数学王国中畅游 [LCT+泰勒展开]

题面

LOJ传送门

思路

1226867-20181012164822586-601286560.png

这里很重要

它提示我们,把给定的三个函数泰勒展开,并用LCT维护每一项泰勒展开式的值,维护十几项就满足了题目的精度要求

我们考虑一个函数在0位置的泰勒展开

$f(x)=\sum_{i=0}^{\infty} \frac{x^i f^{(i)}(0)}{i!}$

发现后面式子里面的$\frac{x^i}{x!}$可以留到询问时候处理,我们只需要维护$\sum_{i=0}^{\infty} f^{(i)}(0)$即可

对于$f(x)=sin(ax+b)$,其导函数如下:

$f^{(4n)}(x)=a^{4n}sin(ax+b)$

$f^{(4n+1)}(x)=a^{4n+1}cos(ax+b)$

$f^{(4n+2)}(x)=-a^{4n+2}sin(ax+b)$

$f^{(4n+3)}(x)=-a^{4n+3}cos(ax+b)$

对于$f(x)=e^{ax+b}$,其导函数如下:

$f^{(n)}(x)=a^{n}e^{ax+b}$(其实就是乘了一个$a$的幂)

对于$f(x)=ax+b$,其一阶导数为$f'(x)=a$,没有更高阶导数

所以,我们在$x=0$的位置泰勒展开这三个函数,并且LCT维护、询问即可

详见代码

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<cmath>
#define ll long double
using namespace std;
inline int read(){
    int re=0,flag=1;char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
int fa[200010],ch[200010][2],rev[200010];
long double w[200010][15],sum[200010][15],a[200010],b[200010];int tp[200010];
//tp={1,2,3} --> {sin,exp,ax+b}
void calc(int cur){//这里是计算泰勒展开值
        //注意因为我们取的位置是x=0,所以展开以后保存的函数自变量取值为0a+b=b
        ll A=a[cur],B=b[cur],*val=w[cur];register int i;
    switch(tp[cur]){
        case 3://sin(ax+b)
            val[0]=B;val[1]=A;
            for(i=2;i<12;i++) val[i]=0;
            break;
        case 2://exp(ax+b)
            val[0]=exp(B);
            for(i=1;i<12;i++) val[i]=val[i-1]*A;
            break;
        case 1://ax+b
            val[0]=sin(B);
            val[1]=A*cos(B);
            for(i=2;i<12;i++) val[i]=-val[i-2]*A*A;
            break;
        default:assert(0);
    }
}
void update(int cur){
    for(register int i=0;i<12;i++) sum[cur][i]=sum[ch[cur][0]][i]+sum[ch[cur][1]][i]+w[cur][i];
}
void pushrev(int cur){
    if(!cur) return;
    swap(ch[cur][0],ch[cur][1]);
    rev[cur]^=1;
}
void pushdown(int cur){
    if(!rev[cur]) return;
    pushrev(ch[cur][0]);
    pushrev(ch[cur][1]);
    rev[cur]=0;
}
bool nroot(int cur){return ch[fa[cur]][0]==cur||ch[fa[cur]][1]==cur;}
void push(int cur){
    if(nroot(cur)) push(fa[cur]);
    pushdown(cur);
}
bool get(int cur){return ch[fa[cur]][1]==cur;}
void rotate(int x){
    int f=fa[x],ff=fa[f],son=get(x),nr=nroot(f);
    ch[f][son]=ch[x][son^1];
    if(ch[f][son]) fa[ch[f][son]]=f;
    fa[f]=x;ch[x][son^1]=f;
    fa[x]=ff;
    if(nr) ch[ff][ch[ff][1]==f]=x;
    update(f);update(x);
}
void splay(int x){
    push(x);
    for(int f;nroot(x);rotate(x)){
        f=fa[x];
        if(nroot(f)){
            rotate((get(x)==get(f))?f:x);
        }
    }
}
void access(int x){
    for(int y=0;x;y=x,x=fa[x]){
        splay(x);ch[x][1]=y;update(x);
    }
}
void mroot(int u){
    access(u);splay(u);pushrev(u);
}
void link(int u,int v){
    mroot(u);fa[u]=v;
}
void cut(int u,int v){
    mroot(u);access(v);splay(v);
    fa[u]=ch[v][0]=0;update(v);
}
int find(int u){
    access(u);splay(u);
    while(ch[u][0]) u=ch[u][0];
    return u;
}
long double query(int u,int v,long double x){
    mroot(u);access(v);splay(v);
    long double re=0,tmp=1;register int i;
    for(i=0;i<12;i++){
        re+=tmp*(long double)(sum[v][i]);
        tmp/=(long double)(i+1);tmp*=x;
    }
    return re;
}
int n,m;char s[20];
int main(){
    n=read();m=read();scanf("%s",s);int i,t1,t2;double t3,t4;
    for(i=1;i<=n;i++){
        fa[i]=ch[i][0]=ch[i][1]=rev[i]=0;
        tp[i]=read();
        scanf("%lf%lf",&t3,&t4);
        a[i]=t3;b[i]=t4;
        calc(i);
    }
    while(m--){//注意题目中点是从0开始的
        scanf("%s",s);
        if(s[0]=='a'){
            t1=read();t2=read();
            t1++;t2++;
            link(t1,t2);
        }
        if(s[0]=='d'){
            t1=read();t2=read();
            t1++;t2++;
            cut(t1,t2);
        }
        if(s[0]=='m'){
            t1=read();t1++;
            tp[t1]=read();
            scanf("%lf%lf",&t3,&t4);
            a[t1]=t3;b[t1]=t4;
            mroot(t1);calc(t1);update(t1);
        }
        if(s[0]=='t'){
            t1=read();t2=read();scanf("%lf",&t3);
            t1++;t2++;
            if(find(t1)!=find(t2)) puts("unreachable");
            else printf("%.10lf\n",(double)(query(t1,t2,t3)));
        }
    }
}

转载于:https://www.cnblogs.com/dedicatus545/p/9779314.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值