[THUWC2017]在美妙的数学王国中畅游 LCT+泰勒展开+求导
p.s. 复合函数求导时千万不能先带值,再求导.
一定要先将符合函数按照求导的规则展开,再带值.
设 $f(x)=g(h(x))$,则对 $f(x)$ 求导: $f'(x)=h'(x)g'(h(x))$
此题中,我们用 LCT 维护 $x^{i}$ 前的系数和,每次询问时将一条链的系数和提出,将 $x$ 带入其前 15 项即可.
Code:
#include<bits/stdc++.h> using namespace std; #define maxn 500000 #define M 17 #define setIO(s) freopen(s".in","r",stdin) //,freopen(s".out","w",stdout) namespace tree{ #define ls ch[x][0] #define rs ch[x][1] #define lson ch[x][0] #define rson ch[x][0] int ch[maxn][2],f[maxn],op[maxn],rev[maxn]; int sta[maxn]; double s[maxn][30],a[maxn],b[maxn]; int get(int x){ return ch[f[x]][1]==x; } int isrt(int x){ return !(ch[f[x]][0]==x||ch[f[x]][1]==x); } void rever(int x){ if(!x) return; rev[x]^=1; swap(ch[x][0],ch[x][1]); } void pd(int x){ if(!rev[x]||!x) return; if(rev[x]) rever(ch[x][0]),rever(ch[x][1]),rev[x]=0; } void up(int x){ for(int i=0;i<M;++i)s[x][i]=s[ch[x][0]][i]+s[ch[x][1]][i]; if(op[x]==1){ double val=1.00000,Sin=sin(b[x]),Cos=cos(b[x]); for(int i=0;i<M;i+=4){ s[x][i]+=val*Sin,val*=a[x]; s[x][i+1]+=val*Cos,val*=a[x]; s[x][i+2]-=val*Sin,val*=a[x]; s[x][i+3]-=val*Cos,val*=a[x]; } } if(op[x]==2){ double EXP=exp(b[x]),val=1.000000; for(int i=0;i<M;++i){ s[x][i]+=EXP*val,val*=a[x]; } } if(op[x]==3){ s[x][0]+=b[x],s[x][1]+=a[x]; } } void rotate(int x){ int old=f[x],oldf=f[old],which=get(x); if(!isrt(old))ch[oldf][ch[oldf][1]==old]=x; ch[old][which]=ch[x][which^1],f[ch[old][which]]=old; ch[x][which^1]=old,f[old]=x,f[x]=oldf; up(old),up(x); } void splay(int x){ int v=0,u=x; sta[++v]=u; while(!isrt(u)) sta[++v]=f[u],u=f[u]; while(v) pd(sta[v--]); u=f[u]; for(int fa;(fa=f[x])!=u;rotate(x)) if(f[fa]!=u) rotate(get(fa)==get(x)?fa:x); } void Access(int x){ for(int y=0;x;y=x,x=f[x]) splay(x),ch[x][1]=y,up(x); } void makert(int x){ Access(x),splay(x),rever(x); } void split(int x,int y){ makert(x),Access(y),splay(y); } void del(int x,int y){ split(x,y); f[x]=ch[y][0]=0; up(y); } void link(int x,int y){ makert(x),f[x]=y; } int fd(int x){ Access(x); splay(x); while(ch[x][0]) x=ch[x][0]; splay(x); return x; } }; double jc[maxn]; void init(){ jc[0]=1.000; for(int i=1;i<M;++i) jc[i]=jc[i-1]*i; } int main(){ //setIO("input"); init(); char str[20]; int n,m; scanf("%d%d%s",&n,&m,str); for(int i=1;i<=n;++i) scanf("%d%lf%lf",&tree::op[i],&tree::a[i],&tree::b[i]); while(m--){ scanf("%s",str); if(str[0]=='a') { int x,y; scanf("%d%d",&x,&y); ++x,++y; tree::link(x,y); } if(str[0]=='d') { int x,y; scanf("%d%d",&x,&y); ++x,++y; tree::del(x,y); } if(str[0]=='m'){ int x,y; double w,k; scanf("%d%d%lf%lf",&x,&y,&w,&k); ++x; tree::Access(x),tree::splay(x); tree::op[x]=y,tree::a[x]=w,tree::b[x]=k; tree::up(x); } if(str[0]=='t'){ int u,v; double w; scanf("%d%d%lf",&u,&v,&w); ++u,++v; if(tree::fd(u)!=tree::fd(v)){ printf("unreachable\n"); }else{ tree::split(u,v); double ans=0.0,val=1.00000; for(int i=0;i<M;++i){ ans+=(double)tree::s[v][i]*val/jc[i]; val*=w; } printf("%.8e\n",ans); } } } return 0; }