线段树 POJ 2991Crane

7 篇文章 0 订阅
5 篇文章 0 订阅

题目链接:http://poj.org/problem?id=2991

代码风格:www.notonlysuccess.com


题目意思:这是一个n结棍,现在沿y轴放置,从(0,l1)为第0条边,(l1, l2)为第1条边……(l(n-1),l(n))为第n-1条边,操作说明,把第k条边沿顺时针方向旋转a度(第k+1……n跟着第k条边一起旋转),问题:求每次操作以后这个n结棍的末端的坐标

算法:线段树,三角运算

思路:把n结棍每节的长度保存在每个线段树的节点上,如果k旋转a度,那么把(k,n)每个节点全部都加上一个角度,通过三角运算得到这个节点(线段)沿x轴,沿y轴的长度,统计每个节点(线段)的数据,把它汇总到root节点,就可以得到n结棍末端的坐标了。

#include"cstdio"
#include"cstring"
#include"math.h"
using namespace std;

#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
#define mid int m = (r+l) >> 1

double sx[234567 << 2];
double sy[223232 << 2];
int sd[232323 << 2];
int angle[232323 << 2];

void PushUp(int rt)
{
	sx[rt] = sx[rt << 1 ] + sx[rt << 1|1 ];
	sy[rt] = sy[rt << 1 ] + sy[rt << 1|1 ];
}

void build(int l, int r, int rt)
{
	sd[rt] = 0;
	if(l == r)
	{
		scanf("%lf", &sy[rt]);
		sx[rt] = 0;
		return ;
	}
	mid ;
	build(lson);
	build(rson);
	PushUp(rt);
}

void ff(int rt, int sd)
{
	double dd = (sd) * asin(1.0) / 90;
	double x = sx[rt] * cos(dd) - sy[rt] * sin(dd);
	double y = sx[rt] * sin(dd) + sy[rt] * cos(dd);
	sx[rt] = x;
	sy[rt] = y;
}

void PushDown(int rt)
{
	if(sd[rt] != 0)
	{
		ff(rt << 1, sd[rt]);
		ff(rt << 1 | 1, sd[rt]);
		sd[rt << 1] += sd[rt] ; sd[rt << 1 | 1] += sd[rt];
		sd[rt] = 0;
	}
}

void update(int a, int ang, int l, int r, int rt)
{
	if(a < l)
	{
		ff(rt, ang);
		sd[rt] += ang;
		return ;
	}
	mid ;
	PushDown(rt);
	if(a < m)
		update(a, ang, lson);
	update(a, ang, rson);
	PushUp(rt);
}

int main()
{
	int n, m;
	int first =1;
	while(scanf("%d%d", &n, &m) != EOF)
	{
		if(first)
			first = 0;
		else
			printf("\n");
		int i;
		for(i = 1; i <= n; i ++)
			angle[i] = 180;
		build(1, n, 1);
		for(i = 1; i <= m; i ++)
		{
			int a, b;
			scanf("%d%d", &a, &b);
			update(a, b-angle[a], 1, n, 1);
			angle[a] = b;
			printf("%.2lf %.2lf\n",fabs(sx[1])<1e-8?0:sx[1],fabs(sy[1])<1e-8?0:sy[1]);
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值