• loj2289 [THUWC 2017]在美妙的数学王国中畅游(LCT+Taylor展开)


    link

    题目大意:

    你需要维护一个树

    每个点都有个sin(ax+b)或exp(ax+b)或ax+b

    你需要维护一些操作:连边、删边、修改某个点的初等函数、询问某条树链上所有函数带入某个值后权值和或不连通

    保证x在[0,1],带入后得到的值在[0,1]

    允许精度误差在1e-7

    题解:

    由于sin函数和exp函数不是多项式函数,比较cd,并且题目要求我们求的值比较小,我们可以对函数在0.5处求泰勒展开,然后每个点就维护了一个多项式函数

    多项式函数加减后还是多项式函数,就可以通过Link-Cut Tree维护树的形态同时维护函数相加,然后直接代入求值就行

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    struct poly
    {
    	double a[10];
    	poly() { }
    	double getval(double x);
    	void output();
    } val[233333], sum[233333];
    
    const double fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
    int ch[233333][2], fa[233333], st[233333], n, m;
    char type[233], tmp[233];
    bool lazy[233333];
    
    poly operator+(const poly &a, const poly &b)
    {
    	poly ans;
    	ans.a[0] = a.a[0] + b.a[0];
    	ans.a[1] = a.a[1] + b.a[1];
    	ans.a[2] = a.a[2] + b.a[2];
    	ans.a[3] = a.a[3] + b.a[3];
    	ans.a[4] = a.a[4] + b.a[4];
    	ans.a[5] = a.a[5] + b.a[5];
    	ans.a[6] = a.a[6] + b.a[6];
    	ans.a[7] = a.a[7] + b.a[7];
    	ans.a[8] = a.a[8] + b.a[8];
    	ans.a[9] = a.a[9] + b.a[9];
    	return ans;
    }
    
    double poly::getval(double x)
    {
    	return ((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0];
    }
    
    void poly::output()
    {
    	for (int i = 0; i < 10; i++)
    	{
    		if (a[i] >= 0) printf("+");
    		printf("%f", a[i]);
    		for (int j = 0; j < i; j++) printf(" * x");
    	}
    }
    
    poly getpoly(int type, double k, double b)
    {
    	if (type == 1) // y = sin(k * x + b)
    	{
    		poly ans; double tmp = 1, sinval = sin(k * 0.5 + b), cosval = cos(k * 0.5 + b);
    		ans.a[0] =  tmp * sinval / fac[0]; tmp *= k;
    		ans.a[1] =  tmp * cosval / fac[1]; tmp *= k;
    		ans.a[2] = -tmp * sinval / fac[2]; tmp *= k;
    		ans.a[3] = -tmp * cosval / fac[3]; tmp *= k;
    		ans.a[4] =  tmp * sinval / fac[4]; tmp *= k;
    		ans.a[5] =  tmp * cosval / fac[5]; tmp *= k;
    		ans.a[6] = -tmp * sinval / fac[6]; tmp *= k;
    		ans.a[7] = -tmp * cosval / fac[7]; tmp *= k;
    		ans.a[8] =  tmp * sinval / fac[8]; tmp *= k;
    		ans.a[9] =  tmp * cosval / fac[9];
    		return ans;
    	}
    	if (type == 2) // y = exp(k * x + b)
    	{
    		poly ans; double tmp = 1, expval = exp(k * 0.5 + b);
    		ans.a[0] = tmp * expval / fac[0]; tmp *= k;
    		ans.a[1] = tmp * expval / fac[1]; tmp *= k;
    		ans.a[2] = tmp * expval / fac[2]; tmp *= k;
    		ans.a[3] = tmp * expval / fac[3]; tmp *= k;
    		ans.a[4] = tmp * expval / fac[4]; tmp *= k;
    		ans.a[5] = tmp * expval / fac[5]; tmp *= k;
    		ans.a[6] = tmp * expval / fac[6]; tmp *= k;
    		ans.a[7] = tmp * expval / fac[7]; tmp *= k;
    		ans.a[8] = tmp * expval / fac[8]; tmp *= k;
    		ans.a[9] = tmp * expval / fac[9];
    		return ans;
    	}
    	// y = k * x + b
    	poly ans;
    	ans.a[0] = k / 2 + b;
    	ans.a[1] = k;
    	ans.a[2] = ans.a[3] = ans.a[4] = ans.a[5] = ans.a[6] = ans.a[7] = ans.a[8] = ans.a[9] = 0;
    	return ans;
    }
    
    bool nroot(int x) { return ch[fa[x]][0] == x || ch[fa[x]][1] == x; }
    void pushup(int x) { sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + val[x]; }
    void rev(int x) { swap(ch[x][0], ch[x][1]), lazy[x] ^= 1; }
    void pushdown(int x) { if (lazy[x]) { if (ch[x][0]) rev(ch[x][0]); if (ch[x][1]) rev(ch[x][1]); lazy[x] = 0; } }
    void rotate(int x)
    {
    	int y = fa[x], z = fa[y], k = (ch[y][1] == x), w = ch[x][k ^ 1];
    	if (nroot(y)) { ch[z][ch[z][1] == y] = x; } ch[x][k ^ 1] = y, ch[y][k] = w;
    	if (w) { fa[w] = y; } fa[y] = x, fa[x] = z, pushup(y), pushup(x);
    }
    void splay(int x)
    {
    	int y = x, top = 0; st[++top]= y; while (nroot(y)) { st[++top] = y = fa[y]; } while (top > 0) pushdown(st[top--]);
    	while (nroot(x)) { int y = fa[x], z = fa[y]; if (nroot(y)) rotate((ch[y][1] == x) ^ (ch[z][1] == y) ? x : y); rotate(x); }
    }
    void access(int x) { for (int y = 0; x > 0; x = fa[y = x]) splay(x), ch[x][1] = y, pushup(x); }
    void makert(int x) { access(x), splay(x), rev(x); }
    int findrt(int x) { access(x), splay(x); while (ch[x][0]) pushdown(x), x = ch[x][0]; return x; }
    void link(int x, int y) { makert(x); if (findrt(y) != x) fa[x] = y; }
    void cut(int x, int y) { makert(x); if (findrt(y) == x && fa[x] == y && ch[x][1] == 0) ch[y][0] = fa[x] = 0, pushup(y); }
    
    int main()
    {
    	scanf("%d%d", &n, &m); scanf("%s", type);
    	double a, b;
    	for (int t, i = 1; i <= n; i++)
    		scanf("%d%lf%lf", &t, &a, &b), val[i] = sum[i] = getpoly(t, a, b);
    	for (int u, v, c, f, i = 1; i <= m; i++)
    	{
    		scanf("%s", tmp);
    		if (!strcmp(tmp, "appear")) scanf("%d%d", &u, &v), link(u + 1, v + 1);
    		if (!strcmp(tmp, "disappear")) scanf("%d%d", &u, &v), cut(u + 1, v + 1);
    		if (!strcmp(tmp, "travel"))
    		{
    			double x;
    			scanf("%d%d%lf", &u, &v, &x), u++, v++;
    			makert(u);
    			if (findrt(v) != u) puts("unreachable");
    			else
    			{
    				printf("%.10f
    ", sum[v].getval(x - 0.5));
    			}
    		}
    		if (!strcmp(tmp, "magic"))
    		{
    			double a, b;
    			scanf("%d%d%lf%lf", &c, &f, &a, &b), c++;
    			splay(c), val[c] = getpoly(f, a, b), pushup(c);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    搭建第一个web项目:Struts+hibernate+spring配置(annotation)
    Visual Studio
    Javascript的性能瓶颈
    导出数据库文档的最简单的方式
    long类型在C#和C++中的异同
    GDI+创建Graphics对象的2种方式
    jQuery中click()与trigger方法的区别
    使用VS调试64位应用程序
    ASP.NET中多个相同name的控件在后台正确取值
    js中的eval方法转换对象时,为何一定要加上括号?
  • 原文地址:https://www.cnblogs.com/oier/p/10495926.html
Copyright © 2020-2023  润新知