• P4546 [THUWC2017]在美妙的数学王国中畅游


    $ color{#0066ff}{ 题目描述 }$

    学渣小R被大学的数学课程虐得生活不能自理,微积分的成绩曾是他在教室里上的课的最低分。然而他的某位陈姓室友却能轻松地在数学考试中得到满分。为了提升自己的数学课成绩,有一天晚上(在他睡觉的时候),他来到了数学王国。

    数学王国中,每个人的智商可以用一个属于([0,1])的实数表示。数学王国中有(n)个城市,编号从(0)(n-1),这些城市由若干座魔法桥连接。每个城市的中心都有一个魔法球,每个魔法球中藏有一道数学题。每个人在做完这道数学题之后都会得到一个在([0,1])区间内的分数。一道题可以用一个从([0,1])映射到([0,1])的函数(f(x))表示。若一个人的智商为(x),则他做完这道数学题之后会得到(f(x))分。函数fff有三种形式:

    1. 正弦函数(sin(a x + b) (a in [0,1], b in [0,pi],a+bin[0,pi]))
    2. 指数函数(e^{ax+b} (ain [-1,1], bin [-2,0], a+bin [-2,0]))
    3. 一次函数(ax + b (ain [-1,1],bin[0,1],a+bin [0,1]))

    数学王国中的魔法桥会发生变化,有时会有一座魔法桥消失,有时会有一座魔法桥出现。但在任意时刻,只存在至多一条连接任意两个城市的简单路径(即所有城市形成一个森林)。在初始情况下,数学王国中不存在任何的魔法桥。

    数学王国的国王拉格朗日很乐意传授小R数学知识,但前提是小R要先回答国王的问题。这些问题具有相同的形式,即一个智商为(x)的人从城市(u)旅行到城市(v)(即经过(u)(v)这条路径上的所有城市,包括(u)(v))且做了所有城市内的数学题后,他所有得分的总和是多少。

    (color{#0066ff}{输入格式})

    第一行两个正整数 (n,m)和一个字符串(type)。表示数学王国中共有(n)座城市,发生了(m)个事件,该数据的类型为(type)(type)字符串是为了能让大家更方便地获得部分分,你可能不需要用到这个输入。其具体含义在【限制与约定】中有解释。

    接下来(n)行,第(i)行表示初始情况下编号为 (i) 的城市的魔法球中的函数。一个魔法用一个整数 (f) 表示函数的类型,两个实数 (a,b) 表示函数的参数,若

    1. (f=1),则函数为(f(x)=sin(ax+b)(a in [0,1], b in [0,pi],a+bin[0,pi]))
    2. (f=2),则函数为(f(x)=e^{ax+b}(ain[-1,1],bin[-2,0],a+bin[-2,0]))
    3. (f=3),则函数为(f(x)=ax+b(ain[-1,1],bin[0,1],a+bin[0,1]))

    接下来 (m) 行,每行描述一个事件,事件分为四类。

    1. appear u v 表示数学王国中出现了一条连接(u)(v)这两座城市的魔法桥((0le u,v < n, u e v)),保证连接前(u)(v)这两座城市不能互相到达。
    2. disappear u v 表示数学王国中连接(u)(v)这两座城市的魔法桥消失了,保证这座魔法桥是存在的。
    3. magic c f a b 表示城市(c)的魔法球中的魔法变成了类型为(f),参数为(a,b)的函数
    4. travel u v x 表示询问一个智商为(x)的人从城市(u)旅行到城市(v)(即经过(u)(v)这条路径上的所有城市,包括(u)(v))后,他得分的总和是多少。若无法从(u)到达(v),则输出一行一个字符串 unreachable

    (color{#0066ff}{输出格式})

    对于每个询问,输出一行实数,表示得分的总和。

    (color{#0066ff}{输入样例})

    3 7 C1
    1 1 0
    3 0.5 0.5
    3 -0.5 0.7
    appear 0 1
    travel 0 1 0.3
    appear 0 2
    travel 1 2 0.5
    disappear 0 1
    appear 1 2
    travel 1 2 0.5
    

    (color{#0066ff}{输出样例})

    9.45520207e-001
    1.67942554e+000
    1.20000000e+000
    

    (color{#0066ff}{数据范围与提示})

    对于100%的数据,(1le nle 100000, 1le m le 200000)

    本题共有20个数据点,每个数据点5分。

    测试点 (n) (m) 数据类型
    (1) (leq 100) (leq 200) C1
    (2-5) (leq 100000) (leq 200000) A0
    (6) null null B0
    (7-8) null null D0
    (9-14) null null A1
    (15-17) null null C1
    (18-20) null null D1

    数据类型的含义:

    A:不存在 disappear 事件,且所有appear事件中的(u=v-1)

    B:不存在 disappear 事件

    C:所有的 travel 事件经过的城市总数 (le 5000000)(不可到达的城市对不计入在内)

    D:无限制

    0:所有 travel 事件中,(x=1)(即所有人的智商均为(1)

    1:无限制

    【评分标准】

    如果你的答案与标准答案的相对误差在(10^{-7})以内或绝对误差在(10^{-7})以内,则被判定为正确。

    如果你的所有答案均为正确,则得满分,否则得0分。

    请注意输出格式:每行输出一个答案,答案只能为 unreachable 或者一个实数(建议使用科学计数法表示)。每行的长度不得超过50。错误输出格式会被判定为0分。

    【小R教你学数学】

    若函数(f(x))(n)阶导数在([a,b])区间内连续,则对(f(x))(x_0(x_0in[a,b]))处使用(n)次拉格朗日中值定理可以得到带拉格朗日余项的泰勒展开式

    (f(x)=f(x_0)+frac{f'(x_0)(x-x_0)}{1!}+frac{f''(x_0)(x-x_0)^2}{2!}+ cdots +frac{f^{(n-1)}(x_0)(x-x_0)^{n-1}}{(n-1)!}+frac{f^{(n)}(xi)(x-x_0)^n}{n!},xin[a,b])

    其中,当(x>x_0)时,(xiin[x_0,x])。当(x<x_0)时,(xiin[x,x_0])

    (f^{(n)})表示函数(f)(n)阶导数

    (color{#0066ff}{题解})

    根据题目显然我们要写一个LCT

    然后维护这些函数的和

    但是这些函数没有办法直接相加,于是良心出题人让我们进行泰勒展开

    然后就成了一个多项式,就可以加了

    据说在0.5处展开只用展开8项就行

    蒟蒻在0处展开了11项。。。

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int maxn = 2e5 + 10;
    const int inf = 0x7fffffff;
    struct Tylar{
        double a[12];
    	Tylar() { memset(a, 0, sizeof a); }
        Tylar(int tp, double aa, double bb) {
            if(tp == 1) {
                double now = 1, x = sin(bb), y = cos(bb);
                for(int i = 1; i <= 11; i++, x = -x, now *= aa, std::swap(x, y)) a[i] = now * x;
    		}
            if(tp == 2) {
                bb = exp(bb);
                for(int i = 1; i <= 11; i++, bb *= aa) a[i] = bb;
    		}
    		if(tp == 3) {
    			*this = Tylar();
    			a[1] = bb, a[2] = aa;
            }
        }
        friend Tylar operator + (const Tylar &a,const Tylar &b) {
            Tylar c;
            for(int i = 1; i <= 11; i++) c.a[i] = a.a[i] + b.a[i];
            return c;
        }
    	double getans(double x) {
            double ans = 0;
            for(int i = 11; i >= 1; i--) ans = a[i] + ans * x / i;
            return ans;
        }
    };
    
    struct LCT {
    protected:
        struct node {
            node *ch[2], *fa;
            int rev;
            Tylar val, tot;
            node(int rev = 0): rev(rev) { ch[0] = ch[1] = fa = NULL; }
    		bool ntr() { return fa && (fa->ch[1] == this || fa->ch[0] == this); }
    		void trn() { std::swap(ch[0], ch[1]), rev ^= 1; }
            bool isr() { return fa->ch[1] == this; }
            void upd(){
                tot = val;
                if(ch[0]) tot = tot + ch[0]->tot;
                if(ch[1]) tot = tot + ch[1]->tot;
            }
            void dwn() {
                if(!rev) return;
                if(ch[0]) ch[0]->trn();
                if(ch[1]) ch[1]->trn();
                rev = 0;
            }
        }pool[maxn];
        void rot(node* x) {
            node *y = x->fa, *z = y->fa;
    		bool k = x->isr(); node *w = x->ch[!k];
            if(y->ntr()) z->ch[y->isr()] = x;
    		(x->ch[!k] = y)->ch[k] = w;
    		(y->fa = x)->fa = z;
            if(w) w->fa = y;
            y->upd(), x->upd();
    	}
        void splay(node *o) {
            static node *st[maxn];
            int top;
    		st[top = 1] = o;
            while(st[top]->ntr()) st[top + 1] = st[top]->fa, top++;
            while(top) st[top--]->dwn();
    		while(o->ntr()) {
    			if(o->fa->ntr()) rot(o->isr() ^ o->fa->isr()? o : o->fa);
    			rot(o);
    		}
        }
        void access(node *x) {
    		for(node *y = NULL; x; x = (y = x)->fa)
    			splay(x), x->ch[1] = y, x->upd();
        }
        void makeroot(node *x) { access(x), splay(x), x->trn(); }
        node *findroot(node *o){
    		access(o), splay(o);
    		while(o->dwn(), o->ch[0]) o = o->ch[0];
    		return splay(o), o;
        }
    public:
        void link(int l, int r) {
    		node *x = pool + l, *y = pool + r;
    		makeroot(x), x->fa = y;
    	}
        void cut(int l, int r) { 
    		node *x = pool + l, *y = pool + r;
    		makeroot(x), access(y), splay(y);
    		y->ch[0] = x->fa = NULL;
    		y->upd();
    	}
        void change(int id, int tp, double a, double b) {
    		node *o = pool + id;
    		splay(o);
    		o->val = Tylar(tp, a, b);
    		o->upd();
    	}
        Tylar query(int l, int r) { 
    		node *x = pool + l, *y = pool + r;
    		makeroot(x), access(y), splay(y);
            return y->tot;
    	}
    	bool init(int l, int r) { return findroot(pool + l) == findroot(pool + r); }
    }s;
    char getch() {
    	char ch;
    	while(!isalpha(ch = getchar()));
    	return ch;
    }
    int main(){
        int n = in(), m = in(); in();
    	double a, b;
    	for(int i = 0; i <= n - 1; i++) {
            int tp = in();
            scanf("%lf%lf", &a, &b);
            s.change(i, tp, a, b);
        }
    	int c, d;
    	while(m --> 0) {
    		char ch = getch();
            if(ch == 'a') s.link(in(), in());
            if(ch == 'd') s.cut(in(), in());
            if(ch == 'm') {
    			c = in(), d = in();
                scanf("%lf%lf", &a, &b);
                s.change(c, d, a, b);
    		}
    		if(ch == 't') {
    			c = in(), d = in();
                scanf("%lf", &a);
                if(s.init(c, d)) printf("%.10f
    ", s.query(c, d).getans(a));
    			else puts("unreachable");
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Java 使用 EasyExcel 实现简单的读写操作
    Java上传文件到阿里云对象存储器OSS
    Springboot 项目解决跨域的问题
    Java 使用 Kafka 发布信息与消费消息
    安装PHPldapAdmin出现You don't have permission to access /phpldapadmin/ on this server.问题
    LDAP安装、LDAP数据迁移、LDAP卸载指南及PHPldapAdmin管理软件安装
    LDAP数据备份与数据恢复
    docker 启动所有镜像
    详解GET 和 POST请求的本质区别
    如何使用 markdown
  • 原文地址:https://www.cnblogs.com/olinr/p/10495811.html
Copyright © 2020-2023  润新知