P4546 在美妙的数学王国中畅游

Luogu 链接

题意

\(n\) 个点,编号 \(0\sim n-1\),每个点上都有个函数。一个函数有 \(3\) 个参数,即 \(opt,a,b\)

  • \(opt=1\) 时,\(f(x)=\sin(ax+b),a\in[0,1],b\in[0,\pi],a+b\in[0,\pi]\)
  • \(opt=2\) 时,\(f(x)=e^{ax+b},a\in[-1,1],b\in[-2,0],a+b\in[-2,0]\)
  • \(opt=3\) 时,\(f(x)=ax+b,a\in[-1,1],b\in[0,1],a+b\in[0,1]\)

我们设点 \(u\) 上的函数为 \(f_u(x)\)

现在要支持以下四种操作:

  • 连接点 \(u\) 和点 \(v\),保证连接前 \(u\)\(v\) 不连通。
  • 切断连接点 \(u\) 和点 \(v\) 的边,保证这条边存在。
  • 修改 \(f_u(x)\) 的参数。
  • 给定点 \(u\)\(v\) 以及实数 \(x\in[0,1]\)
    \(u\)\(v\) 不连通,输出 unreachable
    否则令 \(u\)\(v\) 这条链的点组成的集合为 \(list_{u,v}\),求 \(\displaystyle\sum_{i\in list_{u,v}}f_i(x)\)

现在给出 \(n\) 个点初始的 \(f_i(x)\),并给出 \(q\) 个操作,对于每个操作 \(4\) 输出答案。

数据范围:\(1\le n\le10^5,1\le q\le2\times10^5\)

思路

如果函数都是多项式函数,那么这道题是易于用 LCT 维护的,只需维护各项的系数即可。

但是题目中却有个正弦函数和指数函数,非常不好处理。
注意到题面的最后有提到泰勒展开, 当我们想将这种乱七八糟的函数化成多项式时,可以使用泰勒展开。

所以思路就很显然了:维护函数在 \(x=0\) 处的泰勒展开形式的各项的系数。

我觉得大家都会求导所以公式推导就不放了。

我的程序中是保留了 \(20\) 位。

程序

AC 记录

#include<bits/stdc++.h>
#define forUp(i,a,b) for(int i=(a);i<=(b);++i)
#define forUP(i,a,b) for(int i=(a);i<(b);++i)
#define forDown(i,a,b) for(int i=(a);i>=(b);--i)
#define forG(u,v) for(int __i=head[u],v=to[__i];__i;__i=nxt[__i],v=to[__i])
#define pb emplace_back
using ll=long long;using ull=unsigned long long;using uint=unsigned int;using db=double;using ld=long db;using pii=std::pair<int,int>;using pdi=std::pair<db,int>;using vl=__int128;using uvl=unsigned __int128;
constexpr int INF=0x3f3f3f3f,MINF=0xcfcfcfcf;constexpr long long INFLL=0x3f3f3f3f3f3f3f3f,MINFLL=0xcfcfcfcfcfcfcfcf;constexpr double INFDB=1e50,eps=1e-9;
template<class _Tp>void chkMax(_Tp &x,const _Tp &y){x<y?x=y:0;}template<class _Tp>void chkMin(_Tp &x,const _Tp &y){x>y?x=y:0;}
constexpr int N=1e5+10;int __test_num=1,__test_id;using namespace std;void __init();

int n,q,f,u,v;ld a,b,x;char op[10];

namespace LCT{
	ld derivative(int f,int times,ld x){
		if(f==1){
			switch(times&3){
				case 0:return sin(x);
				case 1:return cos(x);
				case 2:return -sin(x);
				case 3:return -cos(x);
			}
		}
		if(f==2)return exp(x);
		if(f==3){
			if(times==0)return x;
			if(times==1)return 1;
			return 0;
		}
	}
	constexpr int times=20;
	struct Function{
		ld factor[times];
		friend Function operator+(const Function &f,const Function &g){
			Function h;
			forUP(i,0,times)h.factor[i]=f.factor[i]+g.factor[i];
			return h;
		}
		ld operator()(ld x){
			ld res=0;
			forDown(i,times-1,0)res=res*x+factor[i];
			return res;
		}
		void set(int f,ld a,ld b){
			ld tmp=1;
			forUP(i,0,times){
				factor[i]=tmp*derivative(f,i,b);
				tmp=tmp*a/(i+1);
			}
		}
	};
	int fa[N],son[N][2];Function function[N],sumFunction[N];bool rev[N];
	bool nroot(int node){return son[fa[node]][0]==node||son[fa[node]][1]==node;}
	void pushup(int node){
		sumFunction[node]=function[node];
		if(son[node][0])sumFunction[node]=sumFunction[node]+sumFunction[son[node][0]];
		if(son[node][1])sumFunction[node]=sumFunction[node]+sumFunction[son[node][1]];
	}
	void modifyRev(int node){
		rev[node]^=1;
	    swap(son[node][0],son[node][1]);
	}
	void pushdown(int node){
		if(rev[node]){
			if(son[node][0])modifyRev(son[node][0]);
			if(son[node][1])modifyRev(son[node][1]);
			rev[node]=0;
		}
	}
	void rotate(int node){
		int father=fa[node],grand=fa[father],dir=son[father][1]==node,tmp=son[node][!dir];
		if(nroot(father))son[grand][son[grand][1]==father]=node;
		son[node][!dir]=father,son[father][dir]=tmp;
		if(tmp)fa[tmp]=father;
		fa[father]=node,fa[node]=grand;
		pushup(father);pushup(node);
	}
	void clearTag(int node){
		if(nroot(node))clearTag(fa[node]);
		pushdown(node);
	}
	void splay(int node){
		clearTag(node);
		while(nroot(node)){
			int father=fa[node],grand=fa[father];
			if(nroot(father))rotate((son[father][0]==node)^(son[grand][0]==father)?node:father);
			rotate(node);
		}
		pushup(node);
	}
	int access(int node){
		int tmp=0;
		for(;node;node=fa[tmp=node])splay(node),son[node][1]=tmp,pushup(node);
		return tmp;
	}
	void makeRoot(int node){
		access(node);splay(node);
		modifyRev(node);
	}
	int findRoot(int node){
		access(node);splay(node);
		while(son[node][0])pushdown(node),node=son[node][0];
		splay(node);
		return node;
	}
	void split(int node1,int node2){
		makeRoot(node1);
		access(node2);splay(node2);
	}
	void link(int node1,int node2){
		makeRoot(node1);
		if(findRoot(node2)!=node1)makeRoot(node2),fa[node1]=node2;
	}
	void cut(int node1,int node2){
		makeRoot(node1);
		if(findRoot(node2)==node1&&fa[node2]==node1&&!son[node2][0]){
			fa[node2]=son[node1][1]=0;
			pushup(node1);
		}
	}
	void build(){
		forUp(node,1,n){
			scanf("%d%Lf%Lf",&f,&a,&b);
			function[node].set(f,a,b);
			pushup(node);
		}
	}
	void update(int node,int f,ld a,ld b){
		makeRoot(node);
		function[node].set(f,a,b);
		pushup(node);
	}
	ld query(int node1,int node2,ld x){
		split(node1,node2);
		return sumFunction[node2](x);
	}
}using LCT::findRoot,LCT::link,LCT::cut,LCT::build,LCT::update,LCT::query;

void __solve(int __test_id){
	scanf("%d%d%s",&n,&q,op);
	build();
	while(q--){
		scanf("%s",op);
		if(op[0]=='a'){
			scanf("%d%d",&u,&v),++u,++v;
			link(u,v);
		}
		if(op[0]=='d'){
			scanf("%d%d",&u,&v),++u,++v;
			cut(u,v);
		}
		if(op[0]=='m'){
			scanf("%d%d%Lf%Lf",&u,&f,&a,&b),++u;
			update(u,f,a,b);
		}
		if(op[0]=='t'){
			scanf("%d%d%Lf",&u,&v,&x),++u,++v;
			if(findRoot(u)!=findRoot(v))printf("unreachable\n");
			else printf("%.10Lf\n",query(u,v,x));
		}
	}
}
signed main(){
	__init();
	forUp(i,1,__test_num)__solve(i);
	return 0;
}
void __init(){
	//const string __file_name="test";freopen((__file_name+".in").c_str(),"r",stdin);freopen((__file_name+".out").c_str(),"w",stdout);
	//scanf("%d",&__test_num);
}
posted @ 2025-08-27 18:17  LXcjh4998  阅读(4)  评论(0)    收藏  举报