1. 程式人生 > >[LOJ2289][THUWC2017]在美妙的數學王國中暢遊:LCT+泰勒展開

[LOJ2289][THUWC2017]在美妙的數學王國中暢遊:LCT+泰勒展開

分析

又有毒瘤出題人把數學題出在樹上了。

根據泰勒展開,有:

\[e^x=1+\frac{1}{1!}x+\frac{1}{2!}x^2+\frac{1}{3!}x^3+...\]

\[sin(x)=x-\frac{1}{3!}x^3+\frac{1}{5!}x^5-...\]

然而題目裡\(x\)的位置是一個\(ax+b\)怎麼辦啊?直接根據二項式定理暴力展開就好了。

題目中要求支援加邊刪邊,可以想到肯定是LCT。維護一下鏈上所有結點各次項係數和,查詢時直接利用整條鏈的資訊計算答案即可。

計算到\(16\)次項精度就沒有問題了。(主要是湊個整)

程式碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}

const int MAXN=100005;
const int MAXM=200005;
int n,m,top,sta[MAXN];
char opt[15];
double fac[20],c[20][20],powk[20],powb[20];
struct lct{
    int fa,ch[2];
    int opt;
    double k,b;
    double v[20];
    double sum[20];
    bool tag;
}a[MAXN];

inline void pre_process(){
    fac[0]=1;
    rin(i,1,16) fac[i]=fac[i-1]*i;
    c[0][0]=1;
    rin(i,1,16) rin(j,0,i){
        c[i][j]=c[i-1][j];
        if(j) c[i][j]+=c[i-1][j-1];
    }
}

#define lc a[x].ch[0]
#define rc a[x].ch[1]
inline bool isroot(int x){
    return a[a[x].fa].ch[0]!=x&&a[a[x].fa].ch[1]!=x;
}

inline void pushup(int x){
    rin(i,0,16) a[x].sum[i]=a[x].v[i]+a[lc].sum[i]+a[rc].sum[i];
}

inline void pushr(int x){
    std::swap(lc,rc);
    a[x].tag^=1;
}

inline void pushdown(int x){
    if(!a[x].tag) return;
    if(lc) pushr(lc);
    if(rc) pushr(rc);
    a[x].tag=0;
}

inline void info(int x){
    memset(a[x].v,0,sizeof a[x].v);
    if(a[x].opt==1){
        powk[0]=powb[0]=1;
        rin(i,1,16){
            powk[i]=powk[i-1]*a[x].k;
            powb[i]=powb[i-1]*a[x].b;
        }
        int pn=1;
        for(int i=1;i<=16;i+=2){
            rin(j,0,i){
                a[x].v[j]+=pn*powk[j]*powb[i-j]*c[i][j]/fac[i];
            }
            pn=-pn;
        }
    }
    else if(a[x].opt==2){
        powk[0]=powb[0]=1;
        rin(i,1,16){
            powk[i]=powk[i-1]*a[x].k;
            powb[i]=powb[i-1]*a[x].b;
        }
        rin(i,0,16){
            rin(j,0,i){
                a[x].v[j]+=powk[j]*powb[i-j]*c[i][j]/fac[i];
            }
        }
    }
    else{
        a[x].v[1]=a[x].k;
        a[x].v[0]=a[x].b;
    }
    pushup(x);
}

inline void rotate(int x){
    int y=a[x].fa,z=a[y].fa,f=(a[y].ch[1]==x),g=a[x].ch[f^1];
    if(!isroot(y)) a[z].ch[a[z].ch[1]==y]=x;
    a[x].ch[f^1]=y;
    a[y].ch[f]=g;
    if(g) a[g].fa=y;
    a[y].fa=x;
    a[x].fa=z;
    pushup(y);
}

inline void splay(int x){
    int y=x,z=0;
    top=1,sta[1]=y;
    while(!isroot(y)) sta[++top]=y=a[y].fa;
    while(top) pushdown(sta[top--]);
    while(!isroot(x)){
        y=a[x].fa,z=a[y].fa;
        if(!isroot(y)){
            if((a[y].ch[0]==x)==(a[z].ch[0]==y)) rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
    pushup(x);
}

inline void access(int x){
    for(int y=0;x;x=a[y=x].fa){
        splay(x);
        rc=y;
        pushup(x);
    }
}

inline void makeroot(int x){
    access(x);
    splay(x);
    pushr(x);
}

inline int findroot(int x){
    access(x);
    splay(x);
    while(lc) x=lc;
    return x;
}

inline void split(int x,int y){
    makeroot(x);
    access(y);
    splay(y);
}

inline void link(int x,int y){
    makeroot(x);
    a[x].fa=y;
}

inline void cut(int x,int y){
    split(x,y);
    a[x].fa=0;
    a[y].ch[0]=0;
    pushup(y);
}

inline double query(int x,int y,double iq){
    split(x,y);
    double tt=1,ret=0;
    rin(i,0,16){
        ret+=a[y].sum[i]*tt;
        tt*=iq;
    }
    return ret;
}

int main(){
    pre_process();
    n=read(),m=read();
    scanf("%s",opt+1);
    rin(i,1,n){
        a[i].opt=read();
        scanf("%lf%lf",&a[i].k,&a[i].b);
        info(i);
    }
    while(m--){
        scanf("%s",opt+1);
        if(opt[1]=='a'){
            int x=read()+1,y=read()+1;
            link(x,y);
        }
        else if(opt[1]=='d'){
            int x=read()+1,y=read()+1;
            cut(x,y);
        }
        else if(opt[1]=='m'){
            int x=read()+1;a[x].opt=read();
            scanf("%lf%lf",&a[x].k,&a[x].b);
            getchar();
            splay(x);
            info(x);
        }
        else{
            int x=read()+1,y=read()+1;
            double iq;scanf("%lf",&iq);
            getchar();
            if(findroot(x)!=findroot(y)){
                printf("unreachable\n");
                continue;
            }
            printf("%.8le\n",query(x,y,iq));
        }
    }
    return 0;
}