题意
题意奇奇怪怪,这里就不写了。
( exttt{Data Range:}1leq nleq 10^5,1leq mleq 2 imes 10^5)
题解
为什么你们都是卡在数学方面,难道只有我卡在不晓得怎么维护上面吗
看到下面的题解通篇的泰勒展开,我决定写一篇从 ( exttt{EGF}) 上说明的题解,而且公式也比下面的清晰的多。
首先我们做个热身,先来看 (e^x,sin x,cos x) 对应的 ( exttt{EGF}):
[e^x=sumlimits_{i=0}^{infty}frac{x^i}{i!}
]
[sin x=sumlimits_{i=0}^{infty}frac{(-1)^ix^{2i+1}}{(2i+1)!}
]
[cos x=sumlimits_{i=0}^{infty}frac{(-1)^ix^{2i}}{(2i)!}
]
接下来我们用 (ax) 替换 (x) 得到:
[e^{ax}=sumlimits_{i=0}^{infty}frac{a^ix^i}{i!}
]
[sin (ax)=sumlimits_{i=0}^{infty}frac{(-1)^ia^{2i+1}x^{2i+1}}{(2i+1)!}
]
[cos (ax)=sumlimits_{i=0}^{infty}frac{(-1)^ia^{2i}x^{2i}}{(2i)!}
]
如果写的更直观一点呢?
[e^{ax}=1+ax+frac{a^2x^2}{2!}+frac{a^3x^3}{3!}+cdots
]
[sin(ax)=ax-frac{a^3x^3}{3!}+frac{a^5x^5}{5!}-frac{a^7x^7}{7!}+cdots
]
[cos(ax)=1-frac{a^2x^2}{2!}+frac{a^4x^4}{4!}-frac{a^6x^6}{6!}+cdots
]
接下来就是正题了。
考虑到 (e^{ax+b}=e^{ax}cdot e^{b}),而 (b) 是给定常数,所以
[e^{ax+b}=e^b(1+ax+frac{a^2x^2}{2!}+frac{a^3x^3}{3!}+cdots)=sumlimits_{i=0}^{infty}frac{e^ba^ix^i}{i!}
]
然后根据常见的三角恒等变换公式,我们有
[sin(ax+b)=sin(ax)cos b+cos(ax)sin b
]
而 (b) 是给定的常数,所以
[sin(ax+b)=cos b(ax-frac{a^3x^3}{3!}+frac{a^5x^5}{5!}-frac{a^7x^7}{7!}+cdots)+sin b(1-frac{a^2x^2}{2!}+frac{a^4x^4}{4!}-frac{a^6x^6}{6!}+cdots)
]
[sin(ax+b)=sumlimits_{i=0}^{infty}frac{cos b(-1)^ia^{2i+1}x^{2i+1}}{(2i+1)!}+frac{sin b(-1)^ia^{2i}x^{2i}}{(2i)!}
]
然后维护一下这些 ( exttt{EGF}) 就可以直接做了。我的代码维护到 (15) 项,所以比较慢,但还是能过。(至少不用像鰰一样预处理组合数)
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
typedef long double db;
const ll MAXN=2e5+51;
struct Polynomial{
db cof[16];
Polynomial()
{
memset(cof,0,sizeof(cof));
}
inline Polynomial operator +(const Polynomial &rhs)const
{
Polynomial res;
for(register int i=0;i<16;i++)
{
res.cof[i]=cof[i]+rhs.cof[i];
}
return res;
}
inline db eval(db x)
{
db res=0,cur=1;
for(register int i=0;i<16;i++)
{
res+=cof[i]*cur,cur*=x;
}
return res;
}
inline void op()
{
for(register int i=0;i<16;i++)
{
printf("%.8Lf
",cof[i]);
}
}
};
ll n,m,x,y,typ;
db u,v;
string type,op;
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
namespace LCT{
struct Node{
ll fa,rv,sz;
Polynomial poly,sum;
ll ch[2];
};
struct LinkCutTree{
Node nd[MAXN];
ll st[MAXN];
#define ls nd[x].ch[0]
#define rs nd[x].ch[1]
inline bool nroot(ll x)
{
return nd[nd[x].fa].ch[0]==x||nd[nd[x].fa].ch[1]==x;
}
inline void update(ll x)
{
nd[x].sum=nd[ls].sum+nd[rs].sum+nd[x].poly;
}
inline void reverse(ll x)
{
swap(ls,rs),nd[x].rv^=1;
}
inline void spread(ll x)
{
if(nd[x].rv)
{
ls?reverse(ls):(void)(1),rs?reverse(rs):(void)(1);
nd[x].rv=0;
}
}
inline void rotate(ll x)
{
ll fa=nd[x].fa,gfa=nd[fa].fa;
ll dir=nd[fa].ch[1]==x,son=nd[x].ch[!dir];
if(nroot(fa))
{
nd[gfa].ch[nd[gfa].ch[1]==fa]=x;
}
nd[x].ch[!dir]=fa,nd[fa].ch[dir]=son;
if(son)
{
nd[son].fa=fa;
}
nd[fa].fa=x,nd[x].fa=gfa,update(fa);
}
inline void splay(ll x)
{
ll fa=x,gfa,cur=0;
st[++cur]=fa;
while(nroot(fa))
{
st[++cur]=fa=nd[fa].fa;
}
while(cur)
{
spread(st[cur--]);
}
while(nroot(x))
{
fa=nd[x].fa,gfa=nd[fa].fa;
if(nroot(fa))
{
rotate((nd[fa].ch[0]==x)^(nd[gfa].ch[0]==fa)?x:fa);
}
rotate(x);
}
update(x);
}
inline void access(ll x)
{
for(register int i=0;x;x=nd[i=x].fa)
{
splay(x),rs=i,update(x);
}
}
inline void makeRoot(ll x)
{
access(x),splay(x),reverse(x);
}
inline ll findRoot(ll x)
{
access(x),splay(x);
while(ls)
{
spread(x),x=ls;
}
return x;
}
inline void split(ll x,ll y)
{
makeRoot(x),access(y),splay(y);
}
inline void link(ll x,ll y)
{
makeRoot(x);
if(findRoot(y)!=x)
{
nd[x].fa=y;
}
}
inline void cut(ll x,ll y)
{
makeRoot(x);
if(findRoot(y)==x&&nd[x].fa==y&&!rs)
{
nd[x].fa=nd[y].ch[0]=0,update(y);
}
}
#undef ls
#undef rs
};
}
LCT::LinkCutTree lct;
inline Polynomial sin(db u,db v)
{
Polynomial res;
db sinv=sin(v),cosv=cos(v),pw=1,fact=1;
for(register int i=0;i<16;i++)
{
res.cof[i]=(i&2?-1:1)*(i&1?cosv:sinv)*pw*fact,pw*=u,fact/=(1.0*(i+1));
}
return res;
}
inline Polynomial exp(db u,db v)
{
Polynomial res;
db expv=exp(v),pw=1,fact=1;
for(register int i=0;i<16;i++)
{
res.cof[i]=expv*pw*fact,pw*=u,fact/=1.0*(i+1);
}
return res;
}
inline Polynomial linear(db u,db v)
{
Polynomial res;
res.cof[0]=v,res.cof[1]=u;
return res;
}
int main()
{
n=read(),m=read(),cin>>type;
for(register int i=1;i<=n;i++)
{
typ=read(),scanf("%Lf%Lf",&u,&v);
lct.nd[i].poly=typ==1?sin(u,v):typ==2?exp(u,v):linear(u,v);
}
for(register int i=0;i<m;i++)
{
cin>>op;
if(op=="appear")
{
x=read()+1,y=read()+1,lct.link(x,y);
}
if(op=="disappear")
{
x=read()+1,y=read()+1,lct.cut(x,y);
}
if(op=="magic")
{
x=read()+1,typ=read(),scanf("%Lf%Lf",&u,&v);
lct.splay(x);
lct.nd[x].poly=typ==1?sin(u,v):typ==2?exp(u,v):linear(u,v);
}
if(op=="travel")
{
x=read()+1,y=read()+1,scanf("%Lf",&u);
if(lct.findRoot(x)!=lct.findRoot(y))
{
puts("unreachable");
continue;
}
lct.split(x,y),printf("%.12Lf
",lct.nd[y].sum.eval(u));
}
}
}