「LOJ 2289」「THUWC 2017」在美妙的数学王国中畅游——LCT&泰勒展开

题目大意:

  传送门

  给一个动态树,每个节点上维护一个函数为$f(x)=sin(ax+b)$、$f(x)=e^{ax+b}$、$f(x)=ax+b$中的一个。

  支持删边连边,修改节点上函数的操作。

  每次询问$u$到$v$路径上所有函数带入$x$值的和。

题解:

  给了个泰勒公式

  (粘贴自百度)

  不过……要是会导数这题也应该知道……不会导数给了也是白给……不知道出题人怎么想的……

  话说直接给麦克劳林展开+导数不好吗……

  因为$f(x)=e^x$的导数$f'(x)=e^x$所有当取$x_0=0$时就有其麦克劳林展开:

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

  而$sin(x)$导数为$cos(x)$,$cos(x)$导数为$-sin(x)$。所以当$x_0=0$时发现$f(x)$奇数$i$阶导数为$(-1)^{\frac{i-1}{2}}$,偶数阶导均为0。有其麦克劳林展开:

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

  考虑这题数据范围不需要展开太多,大概20项就够了。

  然后把给的参数$ax+b$带进去得到一个关于$x$的长度为20的多项式,我们LCT的时候维护链上系数和即可。

代码:

#include "bits/stdc++.h"

inline int read (){
    int s=0,k=1;char ch=getchar();
    while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar();
    while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar();
    return s*k;
}

#define double long double

using namespace std;

const int N=1e5+10;

int C[20][20];
long long fac[20];

inline void init() {
    register int i,j;
    for (C[0][0]=i=1;i<20;++i)
        for (C[i][0]=j=1;j<=i;++j)
            C[i][j]=C[i-1][j]+C[i-1][j-1];
    for (fac[0]=i=1;i<20;++i)
        fac[i]=fac[i-1]*i;
}

namespace LCT {
    #define rev(t) (t?t->rev^=1:0)
    #define is_root(t) (!t->fa||(t->fa->son[0]!=t&&t->fa->son[1]!=t))
    #define son(t) (t->fa->son[1]==t)
    #define size(t,s) (t?t->size[s]:0)
    struct node {
        node () {fa=son[0]=son[1]=NULL,rev=0,memset(self,0,sizeof self),memset(size,0,sizeof size);}
        node *fa,*son[2];
        double self[20],size[20];
        int rev;
        inline void pushdown()  {
            if (!rev) return ;
            swap(son[0],son[1]);
            rev(son[0]),rev(son[1]);
            rev=0;
        }
        inline void update() {
            for (int i=0;i<20;++i)
                size[i]=size(son[0],i)+size(son[1],i)+self[i];
        }
        inline double ans(double x) {
            double ans=0,now=1.0;
            for (int i=0;i<20;++i,now*=x)
                ans+=now*size[i];
            return ans;
        }
        inline void calc(int type,double a[],double b[]) {
            memset(self,0,sizeof self);
            if (type==1) {

                for (int i=0;i<20;++i)  if (i%2)
                    for (int j=0;j<=i;++j) {
                        self[j]+=((((i-1)/2)&1)?-1:1)*a[j]*b[i-j]*C[i][j]/fac[i];     
                    }           
            }else if(type==2) {
                for (int i=0;i<20;++i)
                    for (int j=0;j<=i;++j)
                        self[j]+=a[j]*b[i-j]*C[i][j]/fac[i];
            }else self[0]=b[1],self[1]=a[1];
        }

    }tree[N],*tmp[N];
    
    inline void rotate(node *p){
        int a=son(p)^1;node *f=p->fa;
        f->son[a^1]=p->son[a];
        if (p->son[a]) p->son[a]->fa=f;
        p->fa=f->fa;
        if (!is_root(f)) f->fa->son[son(f)]=p;
        f->fa=p,p->son[a]=f,f->update(),p->update();
    }
    
    inline void update(node *p){
        if (!is_root(p)) update(p->fa);
        p->pushdown();
    }
    
    inline void splay(node *p){
        register int pos=0;
        for(node *t=p;;t=t->fa){
            tmp[++pos]=t;
            if(is_root(t)) break;
        }
        for(;pos;--pos) tmp[pos]->pushdown();
        for(;!is_root(p);rotate(p))
            if(!is_root(p->fa)) rotate(son(p)==son(p->fa)?p->fa:p);
    }
    
    inline void access(node *p){
        for(node *pre=NULL;p;pre=p,p=p->fa)
            splay(p),p->son[1]=pre,p->update();
    }
    
    inline void make_root(node *x) {
        access(x),splay(x),x->rev^=1;
    }
    
    inline void link(node *x,node *y) {
        make_root(x);access(y),splay(y),x->fa=y;
        y->update();
    }
    
    inline void cut(node *x,node *y){
        make_root(x),access(y),splay(y);
        x->fa=y->son[0]=NULL;y->update();
    }
    
    inline double query(node *x,node *y,double xx){
        make_root(x),access(y),splay(y);
        return y->ans(xx);
    }
    
    inline int finds(node *x) {
        access(x),splay(x);
        while (x->son[0]) x=x->son[0],x->pushdown();
        return x-tree;
    }
}

int n,m;
double a[20],b[20];

int main (int argc, char const* argv[]){
    //freopen("2289.in","r",stdin);
    init();    
    char opt[20];
    n=read(),m=read(),scanf("%s",opt);
    int type;
    a[0]=b[0]=1.0;
    using namespace LCT;
    for (int i=1;i<=n;++i)  {
        type=read();
        scanf("%Lf%Lf",a+1,b+1);
        for (int j=2;j<20;++j)
            a[j]=a[j-1]*a[1],
            b[j]=b[j-1]*b[1];
        tree[i].calc(type,a,b);   
    }

    int u,v,c;
    double x;
    while (m--) {
        scanf("%s",opt);
        if (opt[0]=='a') {
            u=read()+1,v=read()+1;
            link(&tree[u],&tree[v]);
        }else if (opt[0]=='d') {
            u=read()+1,v=read()+1;
            cut(&tree[u],&tree[v]);
        }
        else if (opt[0]=='m') {
            c=read()+1,type=read();
            scanf("%Lf%Lf",a+1,b+1);
            for (int j=2;j<20;++j)
                a[j]=a[j-1]*a[1],
                b[j]=b[j-1]*b[1];
            make_root(&tree[c]);
            tree[c].calc(type,a,b);
            tree[c].update();
        }
        else {
            u=read()+1,v=read()+1;
            scanf("%Lf",&x);
            if (finds(&tree[u])^finds(&tree[v]))   {
                puts("unreachable");
            }
            else {
                printf("%.8Le\n",query(&tree[u],&tree[v],x));
            }
        }
    }
    return 0;
}

  

posted @ 2018-05-02 21:48  Troywar  阅读(516)  评论(0编辑  收藏  举报