bzoj5020[THUWC 2017]在美妙的数学王国中畅游(LCT)

本文详细解析洛谷2289题的解题思路,利用泰勒级数展开,通过LCT数据结构维护多项式的系数,实现对sin(ax+b)和e^(ax+b)的高效计算。实测表明,仅需展开11项即可AC。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门:https://loj.ac/problem/2289
https://www.lydsy.com/JudgeOnline/problem.php?id=5020


s o l u t i o n solution solution:
题目给了公式就比较容易了
x 0 = 0 x_0=0 x0=0的时候比较容易求解
s i n ( a x + b ) = s i n ( b ) + a c o s ( b ) 1 ! x − a 2 s i n ( b ) 2 ! x 2 − a 3 c o s ( b ) 3 ! x 3 + a 4 s i n ( b ) 4 ! x 4 . . . sin(ax+b)=sin(b)+\frac{acos(b)}{1!}x-\frac{a^2sin(b)}{2!}x^2-\frac{a^3cos(b)}{3!}x^3+\frac{a^4sin(b)}{4!}x^4... sin(ax+b)=sin(b)+1!acos(b)x2!a2sin(b)x23!a3cos(b)x3+4!a4sin(b)x4...
e a x + b = e b + a e b 1 x + a 2 e b 2 ! x 2 + a 3 e b 3 ! x 3 + . . . . . e^{ax+b} =e^b+\frac{ae^b}{1}x+\frac{a^2e^b}{2!}x^2+\frac{a^3e^b}{3!}x^3+..... eax+b=eb+1aebx+2!a2ebx2+3!a3ebx3+.....
a x + b = a x + b ax+b=ax+b ax+b=ax+b
可以发现 x x x只要展开 20 20 20项精度就够了(实测 11 11 11项即可 a c ac ac
然后我们只要用 L C T LCT LCT分别维护 x i x^i xi的系数

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define ls ch[x][0]
#define rs ch[x][1]
int rd()
{
    int sum = 0;char c = getchar();bool flag = true;
    while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
    while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
    if(flag) return sum;
    else return -sum;
}
const int maxn = 101000;
struct tree
{
    int ch[maxn][2],fa[maxn],rev[maxn];
	double v[maxn][15],sigma[maxn][15];
    int q[maxn],top;
    void update(int x){rep(i,0,14) sigma[x][i] = sigma[ls][i] + sigma[rs][i] + v[x][i];}
    void rorate(int x)
    {
        int y = fa[x],z = fa[y],k = ch[y][1] == x;
        if(!isroot(y)) ch[z][ch[z][1] == y] = x;
        fa[x]=z;fa[y]=x;  ch[y][k] = ch[x][k^1];
        ch[x][k^1] = y;   fa[ch[y][k]] = y;
        update(y);update(x);
    }
    bool isroot(int x){return ch[fa[x]][1] != x && ch[fa[x]][0] != x;}
    void pushdown(int x){if(rev[x]){rev[ls] ^= 1;rev[rs] ^= 1;swap(ls,rs);rev[x] = 0;}}
    void splay(int x)
    {
        int k = x;top = 0;
        while(1)
        {
            q[++top] = k;
            if(isroot(k)) break;
            k = fa[k];
        }
        while(top) pushdown(q[top--]);
        while(!isroot(x))
        {
            int y = fa[x],z = fa[y];
            if(!isroot(y)) rorate((ch[y][1] == x)^(ch[z][1] == y)?y:x);
            rorate(x);
        }
    }
    void access(int x){for(int t=0;x;x = fa[t=x]) splay(x),ch[x][1] = t,update(x);}
    void makeroot(int x){access(x);splay(x);rev[x] ^= 1;}
    void link(int x,int y){makeroot(x);fa[x] = y;}
    void split(int x,int y){makeroot(x);access(y);splay(y);} 
    void cut(int x,int y){
        makeroot(x);access(y);splay(y);
        fa[x] = ch[y][ch[y][1] == x] = 0;update(y);
    }    
	int findroot(int x){access(x);splay(x);while(ls)x=ls;return x;}
}T;
int n,m;
ll fac[20];
char s[20];
void change(int op,int x,double a,double b)
{
	if(op == 1)
	{//
	    double pi=1,C = cos(b),S = sin(b);int f;
		rep(i,0,14)
		{
			f = (i>>1&1)?-1:1;
			T.v[x][i] = f*pi*(i&1?C:S)/fac[i];
			pi *= a;
		}
	}
	else
	if(op == 2)
	{
		double e = exp(b),pi = 1;
		rep(i,0,14)
		{
			T.v[x][i] = pi*e/fac[i];
			pi *= a;
		}
	}
	else 
	{
		T.v[x][0] = b;T.v[x][1] = a;
		rep(i,2,14) T.v[x][i] = 0;
	}
}
void init()
{
	fac[0] = 1;
	rep(i,1,14) fac[i] = fac[i-1]*i;
	n = rd();m = rd();scanf("%s",s+1);
	rep(i,1,n)
	{
		int k = rd();double x,y;
		scanf("%lf%lf",&x,&y);
		change(k,i,x,y);
	}
}
double query(int u,int v,double x)
{
	T.makeroot(u);T.access(v);T.splay(v);
	double ans = 0,tmp = 1;
	rep(i,0,14)
	    ans += tmp*T.sigma[v][i],tmp *= x;
	return ans;
}
int main()
{
	init();
	rep(i,1,m)
	{
		scanf("%s",s+1);
		int x,y;
		if(s[1] == 'a')
		{
			x = rd()+1,y = rd()+1;
			T.link(x,y);
		}
		else
		if(s[1] == 'd')
		{
			x = rd()+1,y = rd()+1;
			T.cut(x,y);
		}
		else
		if(s[1] == 'm')
		{
			int x = rd()+1,k = rd();
			double a,b;
			T.makeroot(x); 
			scanf("%lf%lf",&a,&b);
			change(k,x,a,b);
			T.update(x);
		}
		else
		{
			int x = rd()+1,y = rd()+1;double z;
			scanf("%lf",&z);
			if(T.findroot(x) != T.findroot(y)) printf("unreachable\n");
			else printf("%.9lf\n",query(x,y,z));
		}
	}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值