[LOJ2289][THUWC2017]在美妙的數學王國中暢遊:LCT+泰勒展開
阿新 • • 發佈:2018-12-27
分析
又有毒瘤出題人把數學題出在樹上了。
根據泰勒展開,有:
\[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; }