poj2991 crane

昨晚上poj进不去,今天补上

线段树+计算几何问题

因为转动第i根线段的时候,所有在其上的线段都要转动相同的角度,因为数据规模为10000,暴力计算会超时O(n*n),所以可以用线段树来解决

线段树维护两个值,一个是需要转动的角度,另一个是首线段起点到尾线段终点的向量

这道题是挑战程序设计竞赛里的,直接抄的代码,关于计算几何的一些地方还没看懂,待日后再补

#include<stdio.h>
#include<math.h>
#define MAX 10005
const double PI = acos(-1.0);
const int ST_SIZE = (1<< 15)-1;

int N,C;
int L[MAX];
int S[MAX],A[MAX];
double vx[ST_SIZE],vy[ST_SIZE];			//各节点的向量
double ang[ST_SIZE];					//各节点的角度
double prv[MAX];						//为了查询角度的变化而保存的当前角度的数组	
//初始化线段树
//k是节点的编号,l、r表示当前节点对应的是[l,r)区间
void init(int k,int l,int r) {
	ang[k]=vx[k]=0.0;
	if(r-l==1) {
		//叶节点
		vy[k]=L[l];
	}
	else {
		//非叶节点
		int chl=k*2+1,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是节点的编号,l,r表示当前节点对应的是[l,r)区间
void change(int s,double a,int v,int l,int r) {
	if (s<=l) return;
	else if (s<r) {
		int chl=v*2+1,chr=v*2+2;
		int m=(l+r)/2;
		change(s,a,chl,l,m);
		change(s,a,chr,m,r);
		if (s<=m) ang[v]+=a;
		double s=sin(ang[v]), c= cos(ang[v]);
		vx[v]= vx[chl]+(c*vx[chr]-s*vy[chr]);		//???????????????
		vy[v]= vy[chl]+(s*vx[chr]+c*vy[chr]);		//vx-vy是将第一条线段转至垂直方向后,头指向尾的向量
	}
}
void solve() {
	init(0,0,N);
	int i;
	for(i=1;i<N;i++) prv[i]=PI;
	for(i=0;i<C;i++) {
		int s=S[i];
		double a=A[i]/360.0*2*PI;
		change(s,a-prv[s],0,0,N);	//a-prv[s]需要转动的角度
		prv[s]=a;
		printf("%.2f %.2f\n",vx[0],vy[0]);
	}
	
}
int main() {
	//freopen("in.txt","r",stdin);
	while(scanf("%d%d",&N,&C)!=EOF) {
		int i;
		for(i=0;i<N;i++) {
			scanf("%d",&L[i]);
		}
		for(i=0;i<C;i++) {
			scanf("%d%d",&S[i],&A[i]);
		}
		solve();
	}	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值