【BZOJ】5020: [THUWC 2017]在美妙的数学王国中畅游-LCT&泰勒展开

本文深入探讨了LCT树链剖分算法在处理复杂路径查询与更新操作中的应用,通过维护路径上的多项式系数,实现了高效的路径求和与修改。特别地,文章详细解释了如何利用LCT树进行节点链接、断开、查询等操作,并通过一个具体的题目实例(bzoj5020),展示了算法的实际应用过程。

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

传送门:bzoj5020


题解

显然是在LCT上维护某些信息。

对于类型 3 : f ( x ) = a x + b 3:f(x)=ax+b 3:f(x)=ax+b只需维护路径上 a , b a,b a,b和。

考虑将 s i n ( a x + b ) , e a x + b sin(ax+b),e^{ax+b} sin(ax+b),eax+b泰勒展开转成多项式后维护前15项(保证精度)即可。


代码

#include<bits/stdc++.h>
using namespace std;
typedef double db;
const int N=1e5+10;

int n,m;
db fnv[15],ans;

char cp;
inline void rd(int &x)
{
	cp=getchar();x=0;
	for(;!isdigit(cp);cp=getchar());
	for(;isdigit(cp);cp=getchar()) x=x*10+(cp^48);
}

inline void trs(db *s)
{
	int i,tp;db a,b,nw=1.0,sn,cs;
	rd(tp);scanf("%lf%lf",&a,&b);
	if(tp==1){
		sn=sin(b),cs=cos(b);
		for(i=0;i<15;i+=4){
		    s[i]=nw*sn*fnv[i];nw*=a;
		    if(i+1<15) s[i+1]=nw*cs*fnv[i+1];nw*=a; 
		    if(i+2<15) s[i+2]=-nw*sn*fnv[i+2];nw*=a;
		    if(i+3<15) s[i+3]=-nw*cs*fnv[i+3];nw*=a;	
		}
	}else if(tp==2){
		sn=exp(b);
		for(i=0;i<15;++i,nw*=a) s[i]=sn*nw*fnv[i];
	}else{
		s[0]=b;s[1]=a;for(i=2;i<15;++i) s[i]=0;
	}
}

namespace LCT{
	#define F(x) t[x].fa
	#define lc(x) t[x].ch[0]
	#define rc(x) t[x].ch[1] 
	#define notrt(x) (F(x)&&((lc(F(x))==x)||(rc(F(x))==x)))
	struct node{
		int fa,ch[2];bool rv;
		db xs[17],ss[17];
		node(){rv=0;memset(ss,0,sizeof(ss));}
	}t[N];
	int stk[N],top;
	
	inline void pu(int x){
		int l=lc(x),r=rc(x),i;
		for(i=0;i<15;++i) t[x].ss[i]=t[x].xs[i]+t[l].ss[i]+t[r].ss[i];
	}
    inline void dn(int x){
    	if(!t[x].rv) return;
    	swap(lc(x),rc(x));
    	if(lc(x)) t[lc(x)].rv^=1;
		if(rc(x)) t[rc(x)].rv^=1;
		t[x].rv=0;
	}
	inline void rot(int x){		
	    int y=F(x),z=F(y),dr=(rc(y)==x);
		t[y].ch[dr]=t[x].ch[dr^1];
		if(t[y].ch[dr]) F(t[y].ch[dr])=y;
		F(x)=z;if(notrt(y)) t[z].ch[(rc(z)==y)]=x;
		F(y)=x;t[x].ch[dr^1]=y;pu(y);
	}
	inline void splay(int x)
	{
		int y=x,z;
		for(;;y=F(y)) {stk[++top]=y;if(!notrt(y)) break;}
		for(;top;--top) dn(stk[top]);
		for(;notrt(x);rot(x)){
			y=F(x);z=F(y);
			if(notrt(y))
			  ((rc(y)==x)^(rc(z)==y))?rot(x):rot(y);
		}
		pu(x);
	}
	inline void setrs(int x,int rs){splay(x);rc(x)=rs;pu(x);}
    inline void access(int x){for(setrs(x,0);F(x);x=F(x)) setrs(F(x),x);}
    inline void mkrt(int x){access(x);splay(x);t[x].rv^=1;}
    inline int fdrt(int x){
	access(x);splay(x);
	for(;lc(x);x=lc(x));
     return x;}
	inline bool iscon(int x,int y){mkrt(x);return x==fdrt(y);}
	inline void lk(int x,int y){mkrt(x);F(x)=y;}
	inline void ct(int x,int y){setrs(x,0);setrs(y,0);F(x)==y?F(x)=0:F(y)=0;}
}

using namespace LCT;
int main(){
	int i,j,x,y;db a,b;fnv[0]=1.0;
	for(i=1;i<15;++i) fnv[i]=fnv[i-1]/(db)i;
	rd(n);rd(m);rd(i);
	for(i=1;i<=n;++i) trs(t[i].xs);
	for(;m;--m){
		for(cp=getchar();!isalpha(cp);cp=getchar());
		if(cp=='a'){rd(x);rd(y);lk(x+1,y+1);}
		else if(cp=='d'){rd(x);rd(y);ct(x+1,y+1);}
		else if(cp=='m'){rd(x);x++;splay(x);trs(t[x].xs);pu(x);}
		else{
			rd(x);rd(y);x++;y++;scanf("%lf",&a);
			if(!iscon(x,y)) puts("unreachable");
			else{
				ans=0;b=1;
				mkrt(x);access(y);splay(y);
				for(i=0;i<15;++i,b*=a) ans+=b*t[y].ss[i];
				printf("%.9lf\n",ans);
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值