1. 程式人生 > >bzoj 5020(洛谷4546) [THUWC 2017]在美妙的數學王國中暢遊——LCT+泰勒展開

bzoj 5020(洛谷4546) [THUWC 2017]在美妙的數學王國中暢遊——LCT+泰勒展開

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=5020

   https://www.luogu.org/problemnew/show/P4546

如果保證 x=1 ,則可以用 LCT 維護每個點的函式值。不然的話就用 LCT 拿出那條鏈,dfs 一下 splay 現算。可以得 60 分。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define db double
using namespace
std; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } const int N=1e5+5; int n,m,fa[N],c[N][2],sta[N],top; db sm[N],vl[N]; bool fx,rev[N]; struct
Node{ int f;db a,b; db cal(db x) { if(f==1)return sin(a*x+b); if(f==2)return exp(a*x+b); if(f==3)return a*x+b; } }a[N]; bool isroot(int cr){return c[fa[cr]][0]!=cr&&c[fa[cr]][1]!=cr;} void pshp(int cr){sm[cr]=sm[c[cr][0]]+sm[c[cr][1]]+vl[cr];} void Rev(int cr){if(rev[cr]){rev[cr]=0
;rev[c[cr][0]]^=1;rev[c[cr][1]]^=1;swap(c[cr][0],c[cr][1]);}} void rotate(int x) { int y=fa[x],z=fa[y],d=(x==c[y][1]); if(!isroot(y))c[z][y==c[z][1]]=x;//!isroot(y) not !isroot(z) !! fa[x]=z; fa[y]=x; fa[c[x][!d]]=y; c[y][d]=c[x][!d]; c[x][!d]=y; if(fx)pshp(y),pshp(x); } void splay(int x) { sta[top=1]=x; for(int cr=x;!isroot(cr);cr=fa[cr])sta[++top]=fa[cr]; for(int i=top;i;i--)Rev(sta[i]); int y,z; while(!isroot(x)) { y=fa[x];z=fa[y]; if(!isroot(y)) ((x==c[y][0])^(y==c[z][0]))?rotate(x):rotate(y); rotate(x); } } void access(int cr) { for(int t=0;cr;splay(cr),c[cr][1]=t,pshp(cr),t=cr,cr=fa[cr]);//pshp()!! } void mkrt(int cr) { access(cr);splay(cr);rev[cr]^=1; } void link(int x,int y) { mkrt(x);fa[x]=y; } void cut(int x,int y) { mkrt(x);access(y);splay(y); fa[x]=c[y][0]=0;if(fx)sm[y]-=vl[x]; } void mdfy(int cr,int f,db a1,db b1) { if(fx)splay(cr),sm[cr]-=vl[cr]; a[cr].f=f;a[cr].a=a1;a[cr].b=b1; if(fx)vl[cr]=a[cr].cal(1),sm[cr]+=vl[cr]; } int fnd(int cr)//root of real tree { while(!isroot(cr))cr=fa[cr];return cr; } db dfs(int cr,db x) { db ret=a[cr].cal(x); if(c[cr][0])ret+=dfs(c[cr][0],x); if(c[cr][1])ret+=dfs(c[cr][1],x); return ret; } void print(db x) { bool fx=0;int t=0; if(x<1){fx=1;while(x<1)x*=10,t++;} if(x>=10){while(x>=10)x/=10,t++;} printf("%.8fe%c%03d\n",x,fx?'-':'+',t); } int main() { n=rdn();m=rdn();char ch[15];scanf("%s",ch); if(ch[1]=='0')fx=1; for(int i=1;i<=n;i++) { a[i].f=rdn();scanf("%lf%lf",&a[i].a,&a[i].b); if(fx)vl[i]=sm[i]=a[i].cal(1); } int u,v;db a,b,x; while(m--) { scanf("%s",ch); if(ch[0]=='a'){u=rdn()+1;v=rdn()+1;link(u,v);} if(ch[0]=='d'){u=rdn()+1;v=rdn()+1;cut(u,v);} if(ch[0]=='m'){u=rdn()+1;v=rdn();scanf("%lf%lf",&a,&b);mdfy(u,v,a,b);} if(ch[0]=='t') { u=rdn()+1;v=rdn()+1;scanf("%lf",&x); mkrt(u);access(v);splay(v); if(fnd(u)!=v)puts("unreachable"); else print(fx?sm[v]:dfs(v,x)); } } return 0; }
View Code

關於本題的求導和泰勒展開可以看這個:https://www.cnblogs.com/zhoushuyu/p/8148732.html

似乎還可以麥克勞林展開:https://www.cnblogs.com/Troywar/p/8982707.html

似乎展開成 12 項的多項式就差不多了,然後可以用 LCT 維護 12 項的係數和,算的時候乘上 xk 再除以階乘就行。

那個 x0 好像取 0 就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define db double
#define ls c[cr][0]
#define rs c[cr][1]
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
using namespace std;
const int N=1e5+5,M=12;
int n,fa[N],c[N][2],sta[N],top; bool rev[N]; db sm[N][M+5],vl[N][M+5],jc[N];
struct Node{
  int f;db a,b;
  Node(int f=0,db a=0,db b=0):f(f),a(a),b(b) {}
  void cz(int cr)
  {
    if(f==1)
      {
    db p[5],lja=1;
    p[0]=sin(b);p[1]=cos(b);p[2]=-p[0];p[3]=-p[1];
    for(int i=0;i<M;i+=4)
      for(int j=0;j<4;j++,lja*=a)sm[cr][i+j]=vl[cr][i+j]=p[j]*lja;
      }
    if(f==2)
      {
    db ml=exp(b),lja=1;
    for(int i=0;i<M;i++,lja*=a)sm[cr][i]=vl[cr][i]=ml*lja;
      }
    if(f==3)
      {
    sm[cr][0]=vl[cr][0]=b; sm[cr][1]=vl[cr][1]=a;
    for(int i=2;i<M;i++)sm[cr][i]=vl[cr][i]=0;
      }
  }
}w[N];
bool isrt(int cr){return c[fa[cr]][0]!=cr&&c[fa[cr]][1]!=cr;}
void pshp(int cr)
{
  for(int i=0;i<M;i++)sm[cr][i]=sm[ls][i]+sm[rs][i]+vl[cr][i];
}
void Rev(int cr){if(rev[cr]){rev[cr]=0;rev[ls]^=1;rev[rs]^=1;swap(ls,rs);}}
void rotate(int x)
{
  int y=fa[x],z=fa[y],d=(x==c[y][1]);
  if(!isrt(y))c[z][y==c[z][1]]=x;
  fa[x]=z;
  fa[y]=x; fa[c[x][!d]]=y;
  c[y][d]=c[x][!d]; c[x][!d]=y;
  pshp(y);pshp(x);
}
void splay(int x)
{
  sta[top=1]=x;
  for(int cr=x;!isrt(cr);cr=fa[cr])sta[++top]=fa[cr];
  for(int i=top;i;i--)Rev(sta[i]);
  int y,z;
  while(!isrt(x))
    {
      y=fa[x];z=fa[y];
      if(!isrt(y))
    ((x==c[y][0])^(y==c[z][0]))?rotate(x):rotate(y);
      rotate(x);
    }
}
void access(int cr)
{
  for(int t=0;cr;splay(cr),rs=t,pshp(cr),t=cr,cr=fa[cr]);//pshp()!!!
}
void mkrt(int cr)
{
  access(cr);splay(cr);rev[cr]^=1;
}
void link(int x,int y)
{
  mkrt(x);fa[x]=y;
}
void cut(int x,int y)
{
  mkrt(x);access(y);splay(y);
  fa[x]=c[y][0]=0;pshp(y);
}
void mdfy(int cr,int f,db a,db b)
{
  splay(cr);
  w[cr]=Node(f,a,b);w[cr].cz(cr);
}
db cal(int cr,db x)
{
  db ret=0,ml=1;
  for(int i=0;i<M;i++,ml*=x)
    ret+=sm[cr][i]*ml/jc[i];
  return ret;
}
int fnd(int cr)
{
  while(!isrt(cr))cr=fa[cr];return cr;
}
void print(db x)
{
  bool fx=0;int t=0;
  if(x<1){fx=1;while(x<1)x*=10,t++;}
  if(x>=10){while(x>=10)x/=10,t++;}
  printf("%.8fe%c%03d\n",x,fx?'-':'+',t);
}
int main()
{
  jc[0]=1;for(int i=1;i<M;i++)jc[i]=jc[i-1]*i;
  n=rdn();int m=rdn();char ch[15];scanf("%s",ch);
  for(int i=1;i<=n;i++)
    w[i].f=rdn(),scanf("%lf%lf",&w[i].a,&w[i].b),w[i].cz(i),pshp(i);//pshp for sm[]
  int u,v;db a,b;
  while(m--)
    {
      scanf("%s",ch);
      if(ch[0]=='a'){u=rdn()+1;v=rdn()+1;link(u,v);}
      if(ch[0]=='d'){u=rdn()+1;v=rdn()+1;cut(u,v);}
      if(ch[0]=='m'){u=rdn()+1;v=rdn();scanf("%lf%lf",&a,&b);mdfy(u,v,a,b);}
      if(ch[0]=='t')
    {
      u=rdn()+1;v=rdn()+1;scanf("%lf",&a);
      mkrt(u);access(v);splay(v);
      if(fnd(u)!=v)puts("unreachable");
      else print(cal(v,a));
    }
    }
  return 0;
}