[LOJ#2289 && BZOJ5020][THUWC 2017]在美妙的数学王国中畅游

16 篇文章 0 订阅

终于找到一个可以交的地方了…
考场上只写了LCT的60分暴力,因为那时候并看不懂什么泰勒展开…

前段时间学了微积分,学了泰勒展开,大概知道了是怎么回事
这里写图片描述
其实题目说的很清楚了…但是那时候就是看不懂,也不会求导什么的。

sin(ax+b) , eax+b ax+b 在x=0处展开可以得到:

sin(ax+b)=sin(b)+acos(b)x1!a2sin(b)x22!a3cos(b)x33!+a4sin(b)x44!+

eax+b=eb+aebx1!+a2ebx22!+a3ebx33!+a4ebx44!+a5ebx55!+

ax+b=ax+b

展开个14层左右,再用LCT来维护森林,每个节点多项式合并一下就可以了

果然我的LCT模板贼慢……
UPD:改了下代码,把func的结构去掉了,原来的取址常数大的一匹……顺便把展开的层数减小了一点

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int N=100010;

int n,m,typ;
double a,b;
char opt[20];

inline void add(double *a,double *b){
}

struct node{
  node *ch[2],*fa;
  int rev;
  double F[25],T[25];
  double val(const double &x){
    double ret=T[0],gx=x;
    long long fac=1;
    for(int i=1;i<=10;i++)
      ret+=T[i]*gx/fac,gx*=x,fac*=i+1;
    return ret;
    }
  void Up(){
    for(int i=0;i<=10;i++) T[i]=F[i];
    if(ch[0]){
        double *C=ch[0]->T;
            for(int i=0;i<=10;i++) 
                T[i]+=C[i];
        }
    if(ch[1]){
        double *C=ch[1]->T;
            for(int i=0;i<=10;i++) 
                T[i]+=C[i];
        }
  }
  void Push(){
    if(!rev) return ;
    swap(ch[0],ch[1]);
    if(ch[0]) ch[0]->rev^=1;
    if(ch[1]) ch[1]->rev^=1;
    rev=0;
  }
}c[N],*st[N];

int top;

inline bool isl(node *x){ return (!x->fa)||(x->fa->ch[0]!=x&&x->fa->ch[1]!=x); }
inline bool iss(node *x){ return x->fa&&x->fa->ch[1]==x; }

void Pushtop(node *x){
  if(!isl(x)) Pushtop(x->fa);
  x->Push();
}

void rot(node *x){
  node *y=x->fa,*z=y->fa; int w=iss(x);
  if(!isl(y)) z->ch[iss(y)]=x; x->fa=z;
  if(y->ch[w]=x->ch[w^1]) y->ch[w]->fa=y;
  x->ch[w^1]=y; y->fa=x; y->Up(); x->Up();
}

inline void splay(node *x){
  Pushtop(x);
  for(;!isl(x);rot(x))
    if(!isl(x->fa))rot(iss(x)^iss(x->fa)?x:x->fa);
}

inline void access(node *x){
  node *t=0;
  for(;x;x=x->fa)
    splay(x),x->ch[1]=t,t=x,x->Up();
}

inline void reverse(node *x){
  access(x); splay(x); x->rev^=1;
}

inline void link(node *x,node *y){
  reverse(x); x->fa=y; access(x); splay(x);
}

inline void cut(node *x,node *y){
  reverse(x); access(y); splay(y); y->ch[0]=x->fa=0; y->Up();
}

inline bool linked(node *x,node *y){
  reverse(x); access(y); splay(y);
  while(y->ch[0]) y=y->ch[0];
  return x==y;
}

double g[4];

inline void set(const int &u,const int &typ,const double &a,const double &b){
  if(typ==1){
    c[u].F[0]=sin(b);
    double ga=a;
    g[0]=sin(b); g[1]=cos(b); g[2]=-sin(b); g[3]=-cos(b); double *C=c[u].F;
    for(int i=1;i<=10;i++)
      C[i]=g[i%4]*ga,ga*=a;
  }
  else if(typ==2){
    double eb=exp(b),ga=a,*C=c[u].F;
    C[0]=eb;
    for(int i=1;i<=10;i++)
      C[i]=eb*ga,ga*=a;
  }
  else{
    double *C=c[u].F;
    C[0]=b,C[1]=a;
    for(int i=2;i<=10;i++) C[i]=0;
  }
}

inline void change(const int &u,const int &typ,const double &a,const double &b){
  access(c+u); splay(c+u);
  set(u,typ,a,b); c[u].Up();
}

inline void Query(const int &u,const int &v,const double &x){
  if(!linked(c+u,c+v)) return (void)puts("unreachable");
  reverse(c+u); access(c+v);
  splay(c+v);
  printf("%.8e\n",c[v].val(x));
}

int u,v;
double x;

int main(){
  scanf("%d%d",&n,&m); scanf("%s",opt);
  for(int i=1;i<=n;i++){
    scanf("%d%lf%lf",&typ,&a,&b);
    set(i,typ,a,b);
  }
  while(m--){
    scanf("%s",opt);
    if(opt[0]=='a')
      scanf("%d%d",&u,&v),link(c+u+1,c+v+1);
    else if(opt[0]=='d')
      scanf("%d%d",&u,&v),cut(c+u+1,c+v+1);
    else if(opt[0]=='m')
      scanf("%d%d%lf%lf",&u,&typ,&a,&b),change(u+1,typ,a,b);
    else
      scanf("%d%d%lf",&u,&v,&x),Query(u+1,v+1,x);
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值