P4546 在美妙的数学王国中畅游
题意
有 \(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\) 位。
程序
#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);
}

浙公网安备 33010602011771号