POJ 2991 Crane

题目大意:

有N根棍子首尾相连,每次更改两个棍子之间的夹角,求最后一个点坐标。


解题思路:

因为前面的角度变了后面的角度也会变,所以显然是个线段树。

但是因为涉及到一点几何知识,我这种智障还是想了蛮久的。


#include<cstdio>
#include<cstring>
#include<cmath>
#define LL long long
#define db double
#define maxn 10010
#define PI acos(-1.0)
#define eps 1e-9
using namespace std;

struct point{
	double x,y;
}p[maxn<<2];
int lazy[maxn<<2],angle[maxn];

int max(int x,int y){
	if (x>y) return x;
	else return y;
}
int min(int x,int y){
	if (x<y) return x;
	else return y;
}
void work(int a,int rt){
	db x=p[rt].x;
	db y=p[rt].y;
	db ang=PI/180*a;
	p[rt].x=cos(ang)*x-sin(ang)*y;
    p[rt].y=sin(ang)*x+cos(ang)*y;
}
void pushup(int rt){
	p[rt].x=p[rt<<1].x+p[rt<<1|1].x;
    p[rt].y=p[rt<<1].y+p[rt<<1|1].y;
}
void pushdown(int rt){
	if (lazy[rt]){
		work(lazy[rt],rt<<1);
		work(lazy[rt],rt<<1|1);
		lazy[rt<<1]+=lazy[rt];
		lazy[rt<<1|1]+=lazy[rt];
		lazy[rt]=0;
	}
}
void build(int l,int r,int rt){
	if (l==r){
		scanf("%lf",&p[rt].y);
		p[rt].x=0;
		return;
	}
	int mid=l+r>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,rt<<1|1);
	pushup(rt);
}
void update(int a,int L,int R,int l,int r,int rt){
	if (L<=l && r<=R){
		lazy[rt]+=a;
		work(a,rt);
		return ;
	}
	pushdown(rt);
	int mid=(l+r)>>1;
	if (L<=mid) update(a,L,R,l,mid,rt<<1);
	if (R>mid) update(a,L,R,mid+1,r,rt<<1|1);
	pushup(rt);
}
int main(){
	int n,m;
	int cnt=0;
	while (scanf("%d%d",&n,&m)==2){
		if (cnt++) puts("");
		build(1,n,1);
		for (int i=1;i<=n;i++) angle[i]=180;
		memset(lazy,0,sizeof(lazy));
		while (m--) {
			int s,a;
			scanf("%d%d",&s,&a);
			int x=(a-angle[s]+360)%360;
			update(x,s+1,n,1,n,1);
			angle[s]=a;
			printf("%.2lf %.2lf\n",p[1].x+eps,p[1].y+eps);
		}
	}
	return 0;
}



你可能感兴趣的:(POJ 2991 Crane)