1. 程式人生 > >BZOJ5020 THUWC2017在美妙的數學王國中暢遊(動態樹)

BZOJ5020 THUWC2017在美妙的數學王國中暢遊(動態樹)

  明擺著的LCT,問題在於如何維護答案。首先注意到給出的泰勒展開式,並且所給函式求導非常方便,肯定要用上這玩意。容易想到展開好多次達到精度要求後忽略餘項。因為x∈[0,1]而精度又與|x-x0|有關,當然是維護x=0.5時的各種東西,粗略算下大概到第13項就可以了。具體要維護的東西當然是對於x的不同次數分別維護一個和。注意編號從0開始。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using
namespace std; #define ll long long #define N 100010 #define lson tree[k].ch[0] #define rson tree[k].ch[1] #define lself tree[tree[k].fa].ch[0] #define rself tree[tree[k].fa].ch[1] char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return
c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,fac[14]; struct data{int ch[2
],fa,rev,op;double a,b,ans[14],f[14]; }tree[N]; double calc(int op,int k,double x,double a,double b) { if (op==1) return ((k&3)<2?1:-1)*pow(a,k)*(k&1?cos(a*x+b):sin(a*x+b)); if (op==2) return pow(a,k)*exp(a*x+b); if (op==3) { if (k==0) return a*x+b; if (k==1) return a; return 0; } } void up(int k){for (int i=0;i<13;i++) tree[k].ans[i]=tree[lson].ans[i]+tree[rson].ans[i]+tree[k].f[i];} void newpoint(int x) { for (int i=0;i<13;i++) tree[x].f[i]=0; for (int i=0;i<13;i++) { double t=calc(tree[x].op,i,0.5,tree[x].a,tree[x].b);double t2=1; for (int j=i;~j;j--) tree[x].f[j]+=t2*t/fac[j]/fac[i-j],t2/=-2; } up(x); } void rev(int k){if (k) swap(lson,rson),tree[k].rev^=1;} void down(int k){if (tree[k].rev) rev(lson),rev(rson),tree[k].rev=0;} int whichson(int k){return rself==k;} bool isroot(int k){return lself!=k&&rself!=k;} void push(int k){if (!isroot(k)) push(tree[k].fa);down(k);} void move(int k) { int fa=tree[k].fa,gf=tree[fa].fa,p=whichson(k); if (!isroot(fa)) tree[gf].ch[whichson(fa)]=k;tree[k].fa=gf; tree[fa].ch[p]=tree[k].ch[!p],tree[tree[k].ch[!p]].fa=fa; tree[k].ch[!p]=fa,tree[fa].fa=k; up(fa),up(k); } void splay(int k) { push(k); while (!isroot(k)) { int fa=tree[k].fa; if (!isroot(fa)) if (whichson(k)^whichson(fa)) move(k); else move(fa); move(k); } } void access(int k){for (int t=0;k;t=k,k=tree[k].fa) splay(k),tree[k].ch[1]=t,up(k);} void makeroot(int k){access(k),splay(k),rev(k);} int findroot(int k){access(k),splay(k);for (;lson;k=lson) down(k);splay(k);return k;} void link(int x,int y){makeroot(x),tree[x].fa=y;} void cut(int x,int y){makeroot(x),access(y),splay(y);tree[x].fa=tree[y].ch[0]=0,up(y);} void modify(int x,int op,double a,double b){access(x),splay(x);tree[x].op=op,tree[x].a=a,tree[x].b=b;newpoint(x);} double query(int u,int v,double x) { makeroot(u),access(v),splay(v); double s=0,t=1; for (int i=0;i<13;i++) { s+=t*tree[v].ans[i]; t*=x; } return s; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5020.in","r",stdin); freopen("bzoj5020.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif fac[0]=1;for (int i=1;i<13;i++) fac[i]=fac[i-1]*i; n=read(),m=read();read(); for (int i=1;i<=n;i++) tree[i].op=read(),scanf("%lf %lf",&tree[i].a,&tree[i].b),newpoint(i); while (m--) { char c=getc(); switch (c) { case 'a':{link(read()+1,read()+1);break;} case 'd':{cut(read()+1,read()+1);break;} case 'm': { int x=read()+1,op=read();double a,b;scanf("%lf %lf",&a,&b); modify(x,op,a,b); break; } case 't': { int u=read()+1,v=read()+1;double x;scanf("%lf",&x); if (findroot(u)!=findroot(v)) printf("unreachable\n"); else printf("%.10f\n",query(u,v,x)); break; } } } return 0; }