题目大意:
给一个动态树,每个节点上维护一个函数为$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 ",query(&tree[u],&tree[v],x)); } } } return 0; }