POJ_2991_Crane_线段树

本来很操蛋的一天,就因为把这道艹哭我两天的题A了而变得好多了微笑


题意:

一个起重机,由n个臂组成,每个臂的臂长已知,初始状态任意两个臂之间的角度为180度,给c个操作,选择第i个臂,将第s和第s+1个臂之间的角度改成a,每次讯问后输出尖端的坐标。


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.

这题是怎么想到线段树忘了,因为我是在挑战的例题里看到它的。。。

对臂建树,每个点维护前半段和后半段之间的角度(具体哪个角看实现方法),以及如果该段第一个臂竖直向上顶端到基点的向量。

每次更新某两个臂之间的角度时,将所有满足loc<=m的点角度都改变相同的数值,因为他们的对比基础都是改变点前面的臂。

然后维护公式是向量旋转。向量(x,y)正方向旋转phi,得到(x*cos(phi)-y*sin(phi), xsin(phi)+y*cos(phi))

公式的原理是设当前坐标为(lcosa,lsina),然后在坐标系上画一下,拆一下sin,cos就行了。

还有,头一次用面向对象写ACM题生气


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<fstream>
using namespace std;
#define mxn 10010
const double pi=acos(-1.0);
int n,c;
double len[mxn],angle[mxn];
class coor{
public:
	double x,y;
	coor(){}
	coor(double a,double b){
		x=a,y=b;
	}
	coor rotate(double ang){
		double tema=cos(ang),temb=sin(ang);
		return coor(x*tema-y*temb,x*temb+y*tema);
	}
	coor operator + (const coor& in)const{
		return coor(x+in.x,y+in.y);
	}
	void print(){
		printf("%.2lf %.2lf\n",x,y);
	}
};
class node{
public:
	int ll,rr;
	coor end;
	double ang;
};
class segment_tree{
private:
	node nd[mxn<<2];
	void merge(int id){
		int ls=id<<1,rs=ls|1;
		nd[id].end=nd[ls].end+nd[rs].end.rotate(nd[id].ang);
	}
public:
	void build(int l,int r,int id){
		nd[id].ll=l;
		nd[id].rr=r;
		if(l==r){
			nd[id].end=coor(0.0,len[l]);
			nd[id].ang=0.0;
			return;
		}
		int m=(l+r)>>1,ls=id<<1,rs=ls|1;
		build(l,m,ls);
		build(m+1,r,rs);
		nd[id].ang=0.0;
		merge(id);
	}
	void update(int loc,double x,int id){
		int m=(nd[id].ll+nd[id].rr)>>1,ls=id<<1,rs=ls|1;
		if(loc<=m){
			nd[id].ang+=x;
		}
		if(nd[id].ll==nd[id].rr)	return;
		if(loc<=m)	update(loc,x,ls);
		else    update(loc,x,rs);
		merge(id);
	}
	void printAns(){
		nd[1].end.print();
	}
}Tree;
void init(){
	Tree.build(0,n-1,1);
	for(int i=0;i<n;++i)	angle[i]=180.0;
}
double convert(double in){
	return in*2*pi/360.0;
}
int main(){
	bool first=true;
	while(scanf("%d%d",&n,&c)!=EOF){
		if(!first){
			puts("");
		}
		first=false;
		for(int i=0;i<n;++i)	scanf("%lf",&len[i]);
		init();
		int s;
		double a;
		for(int q=0;q<c;++q){
			scanf("%d%lf",&s,&a);
			Tree.update(s-1,convert(a-angle[s-1]),1);
			angle[s-1]=a;
			Tree.printAns();
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值