码迷,mamicode.com
首页 > 其他好文 > 详细

北大ACM2991——Crane~~线段树

时间:2015-05-20 16:29:32      阅读:98      评论:0      收藏:0      [点我收藏+]

标签:北大   acm   

最近看到了线段树,对于线段树也是有了初步的了解,还是需要时间继续研究,加深理解。

感觉线段树,个人觉得最主要的是递归过程的理解。

这一题,给定一段绳子,“ 分成 ”N段,起初,每段绳子都是垂直的。然后有C个命令,每个命令包含两个数 i  ,  j,i  是第几段绳子,j 是 i 段绳子旋转到  i + 1 段绳子多经过的角度。也就是  i  和 i + 1 之间的角度是  j。

可以理解成向量,起初每个向量方向向上。

如果结点 i 表示的向量是vx1, vy1。角度是angle,两个儿子节点是chl,chr,那么:

vx1 = vx(chl)+ (cos(angle)* vx(chr)- sin(angle)* vy(chr));

vy1 = vy(chl)+ (sin(angle)* vx(chr)+ cos(angle)* vy(chr));

下面是AC的代码:

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;

const double PI = acos(-1.0);             //PI,直接用3.1415927过不了。
const int MAX_SIZE = (1 << 15) - 1;       //线段树的最大长度
const int MAX_N = 10005;                  //N的最大值
const int MAX_C = 10005;                  //C的最大值
int N, C;
int L[MAX_N], S[MAX_C], A[MAX_C];         //L是每段长度,S是每个命令中的第几段的数组,A是角度数组

double vx[MAX_SIZE], vy[MAX_SIZE];        //各个向量的数组
double angle[MAX_SIZE];                   //各个向量的角度数组

double temp[MAX_SIZE];                    //角度变化而保存的当前角度的数组
//k是结点编号,l,r是区间[l,r]
void init(int k, int l, int r)            //线段树的初始化
{
	angle[k] = vx[k] = 0.0;               //角度都为0,x坐标为0.
	if(r - l == 1)                        //叶子结点的y坐标
	{
		vy[k] = L[l];
	}
	else                                  //非叶子结点
	{
		int chl = k * 2 + 1; int chr = k * 2 + 2;
		init(chl, l, (l + r) / 2);
		init(chr, (l + r) / 2, r);
		vy[k] = vy[chl] + vy[chr];
	}
}
//将s和s+1段的角度变成a
//v是结点编号
void change(int s, double a, int v, int l, int r)
{
	if(s <= l)
		return;
	else if(s < r)         //s>l & s<r
	{
		int chl = 2 * v + 1; int chr = 2 * v + 2;
		int m = (l + r) / 2;
		change(s, a, chl, l, m);
		change(s, a, chr, m, r);
		if(s <= m)
			angle[v] += a;
		double s = sin(angle[v]), c = cos(angle[v]);
		vx[v] = vx[chl] + (c * vx[chr] - s * vy[chr]);   //改变向量
		vy[v] = vy[chl] + (s * vx[chr] + c * vy[chr]);
	}
}

void solve()
{
	init(0, 0, N);                  //初始化
	for(int i = 0; i < N; i++)      //起始每个向量的角度为180度,也就是π
		temp[i] = PI;
	for(int j = 0; j < C; j++)
	{
		int s = S[j];
		double a = A[j] / 360.0 * 2 * PI;
		change(s, a - temp[s], 0, 0, N);
		temp[s] = a;                //角度改变
		printf("%.2lf %.2lf\n\n", vx[0], vy[0]); //输出
	}
}

int main()
{
	while(scanf("%d%d", &N, &C) != EOF)      //输入
	{
		for(int i = 0; i < N; i++)
			scanf("%d", &L[i]);
		for(int j = 0; j < C; j++)
			scanf("%d%d", &S[j], &A[j]);
		solve();
	}
	return 0;
}


北大ACM2991——Crane~~线段树

标签:北大   acm   

原文地址:http://blog.csdn.net/qq_25425023/article/details/45870741

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!