首页 > 代码库 > 线段树区间更新+向量知识——POJ 2991

线段树区间更新+向量知识——POJ 2991

对应POJ题目:点击打开链接


Crane
Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u

Submit Status

Description

ACM has bought a new crane (crane -- je?áb) . The crane consists of n segments of various lengths, connected by flexible joints. The end of the i-th segment is joined to the beginning of the i + 1-th one, for 1 ≤ i < n. The beginning of the first segment is fixed at point with coordinates (0, 0) and its end at point with coordinates (0, w), where w is the length of the first segment. All of the segments lie always in one plane, and the joints allow arbitrary rotation in that plane. After series of unpleasant accidents, it was decided that software that controls the crane must contain a piece of code that constantly checks the position of the end of crane, and stops the crane if a collision should happen. 

Your task is to write a part of this software that determines the position of the end of the n-th segment after each command. The state of the crane is determined by the angles between consecutive segments. Initially, all of the angles are straight, i.e., 180 o. The operator issues commands that change the angle in exactly one joint. 

Input

The input consists of several instances, separated by single empty lines. 

The first line of each instance consists of two integers 1 ≤ n ≤10 000 and c 0 separated by a single space -- the number of segments of the crane and the number of commands. The second line consists of n integers l1,..., ln (1 li 100) separated by single spaces. The length of the i-th segment of the crane is li. The following c lines specify the commands of the operator. Each line describing the command consists of two integers s and a (1 ≤ s < n, 0 ≤ a ≤ 359) separated by a single space -- the order to change the angle between the s-th and the s + 1-th segment to a degrees (the angle is measured counterclockwise from the s-th to the s + 1-th segment).

Output

The output for each instance consists of c lines. The i-th of the lines consists of two rational numbers x and y separated by a single space -- the coordinates of the end of the n-th segment after the i-th command, rounded to two digits after the decimal point. 

The outputs for each two consecutive instances must be separated by a single empty line.

Sample Input

2 1
10 5
1 90

3 2
5 5 5
1 270
2 90

Sample Output

5.00 10.00

-10.00 5.00
-5.00 10.00

Source


题意:有一个吊车由很多个不同长度的线段组成,一开始是一条长直线起点在(0,0),尾节点在(0,sum[n]),每条线段之间的夹角的初始值是180度。然后有一些操作a、 b将第a条线段和a+1之间的夹角变成b度,经过每一次操作都要求出尾节点的坐标。



思路:线段树区间更新;结点值保存该区间的向量及旋转角(注意他给出的不是旋转角)一个区间的向量值=左子区间的向量+右子区间的向量。

求一个向量(x0,y0)逆时针旋转B度后的向量有一个公式:

x1= x0 * cosB - y0 * sinB

 y1 = x0 * sinB + y0 * cosB

顺时针就把-B代入:

x1= x0 * cosB + y0 * sinB

 y1 = -x0 * sinB + y0 * cosB


还有一点很恶心,就是旋转角的计算;用一个angle[i]数组表示第i段线段跟第i-1段线段的夹角,我这里是计顺时针旋转的,我初始化angle[]为180,故每次更新时,旋转角t=angle[i]-b;   angle[i]=b;








#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#define ms(x,y) memset(x,y,sizeof(x))
#define eps 1e-6
const int MAXN=10000+10;
const int INF=1<<30;
using namespace std;
double px[MAXN<<2];
double py[MAXN<<2];
int turn[MAXN<<2];
int angle[MAXN];//第i个线段与第i-1个线段的夹角
//const double pi = acos(-1.0);
const double pi = 3.141592653;

void down(int rt)
{
	if(turn[rt]){
		int t=turn[rt];
		turn[rt<<1]+=t;
		turn[rt<<1|1]+=t;
		//左向量旋转t度
		double x=px[rt<<1], y=py[rt<<1];
		px[rt<<1]=x*cos(t*pi/180) + y*sin(t*pi/180);
		py[rt<<1]=-x*sin(t*pi/180) + y*cos(t*pi/180);

		//右向量旋转t度
		x=px[rt<<1|1], y=py[rt<<1|1];
		px[rt<<1|1]=x*cos(t*pi/180) + y*sin(t*pi/180);
		py[rt<<1|1]=-x*sin(t*pi/180) + y*cos(t*pi/180);

		turn[rt]=0;
	}
}

void buildline(int rt, int left, int right)
{
	if(left==right){
		px[rt]=0.0;
		scanf("%lf", &py[rt]);
		return;
	}
	int mid=(left+right)>>1;
	buildline(rt<<1, left, mid);
	buildline(rt<<1|1, mid+1, right);
	px[rt]=px[rt<<1] + px[rt<<1|1];
	py[rt]=py[rt<<1] + py[rt<<1|1];
}

void updata(int rt, int left, int right, int l, int r, int t)
{
	if(left==l && right==r){
		double x=px[rt], y=py[rt];
		px[rt]=x*cos(t*pi/180) + y*sin(t*pi/180);
		py[rt]=-x*sin(t*pi/180) + y*cos(t*pi/180);
		turn[rt]+=t;
		return;
	}
	down(rt);
	int mid=(left+right)>>1;
	if(mid<l) updata(rt<<1|1, mid+1, right, l, r, t);
	else{
		updata(rt<<1, left, mid, l, mid, t);
		updata(rt<<1|1, mid+1, right, mid+1, r, t);
	}
	px[rt]=px[rt<<1] + px[rt<<1|1];
	py[rt]=py[rt<<1] + py[rt<<1|1];
}

int main()
{
	//freopen("in.txt","r",stdin);
	int N,O,cnt=0;
	while(~scanf("%d%d", &N,&O))
	{
		ms(turn,0);
		for(int i=2; i<=N; i++)
			angle[i]=180;
		if(cnt++) printf("\n");
		buildline(1,1,N);
		int a,b;
		while(O--)
		{
			scanf("%d%d", &a,&b);
			a++;
			int t=angle[a]-b;
			angle[a]=b;
			updata(1,1,N,a,N,t);
			printf("%.2lf %.2lf\n", px[1],py[1]);
		}
	}
	return 0;
}




线段树区间更新+向量知识——POJ 2991