qzqzgfy's blog

By qzqzgfy, history, 10 years ago, In English
E. Robot Arm
                             time limit per test8 seconds
                          memory limit per test256 megabytes
                                    inputstandard input
                                    outputstandard output

Roger is a robot. He has an arm that is a series of n segments connected to each other. The endpoints of the i-th segment are initially located at points (i - 1, 0) and (i, 0). The endpoint at (i - 1, 0) is colored red and the endpoint at (i, 0) is colored blue for all segments. Thus, the blue endpoint of the i-th segment is touching the red endpoint of the (i + 1)-th segment for all valid i.

Roger can move his arm in two different ways:

He can choose some segment and some value. This is denoted as choosing the segment number i and picking some positive l. This change happens as follows: the red endpoint of segment number i and segments from 1 to i - 1 are all fixed in place. Imagine a ray from the red endpoint to the blue endpoint. The blue endpoint and segments i + 1 through n are translated l units in the direction of this ray.  In this picture, the red point labeled A and segments before A stay in place, while the blue point labeled B and segments after B gets translated.

He can choose a segment and rotate it. This is denoted as choosing the segment number i, and an angle a. The red endpoint of the i-th segment will stay fixed in place. The blue endpoint of that segment and segments i + 1 to n will rotate clockwise by an angle of a degrees around the red endpoint.  In this picture, the red point labeled A and segments before A stay in place, while the blue point labeled B and segments after B get rotated around point A.

Roger will move his arm m times. These transformations are a bit complicated, and Roger easily loses track of where the blue endpoint of the last segment is. Help him compute the coordinates of the blue endpoint of the last segment after applying each operation. Note that these operations are cumulative, and Roger's arm may intersect itself arbitrarily during the moves.

Input The first line of the input will contain two integers n and m (1 ≤ n, m ≤ 300 000) — the number of segments and the number of operations to perform.

Each of the next m lines contains three integers xi, yi and zi describing a move. If xi = 1, this line describes a move of type 1, where yi denotes the segment number and zi denotes the increase in the length. If xi = 2, this describes a move of type 2, where yi denotes the segment number, and zi denotes the angle in degrees. (1 ≤ xi ≤ 2, 1 ≤ yi ≤ n, 1 ≤ zi ≤ 359)

Output Print m lines. The i-th line should contain two real values, denoting the coordinates of the blue endpoint of the last segment after applying operations 1, ..., i. Your answer will be considered correct if its absolute or relative error does not exceed 10 - 4.

Namely, let's assume that your answer for a particular value of a coordinate is a and the answer of the jury is b. The checker program will consider your answer correct if  for all coordinates.

Examples input 5 4 1 1 3 2 3 90 2 5 48 1 4 1 output 8.0000000000 0.0000000000 5.0000000000 -3.0000000000 4.2568551745 -2.6691306064 4.2568551745 -3.6691306064

:用线段树维护,将相邻两个节点之间向量作为线段树的叶子节点,然后就可以发现(0,0)加上线段树的总和就是N的坐标,接下来就能发现让某个区间的节点绕前一个节点旋转就相当于让这个区间的向量同时旋转这个角度,这相当于区间修改,而移动一个区间就相当于加长一个向量,这相当于单点修改,由于向量可以相加减并且满足交换律,因此用线段树维护是可以保证正确性的。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <vector>
#include <functional>
#include <ctime>
#include <cstdlib>
#include <sstream>
#include <set>
#include <deque>
#define Rep(i, l, r) for (int i = l; i <= r; ++i)
#define Req(i, l, r) for (int i = l; i >= r; --i)
struct tree{
	double x,y,f;
}t[5000005];
int n,m,opt,pos;
double d,eps=1e-8;
void updata(int k){
	t[k].x=t[k*2].x+t[k*2+1].x;
	t[k].y=t[k*2].y+t[k*2+1].y;
}
double dis(double x,double y){
	return sqrt(x*x+y*y);
}
void pushdown(int k,int l,int r){
	if (l==r) return;
	if (fabs(t[k].f)>eps){
		double ccos=cos(t[k].f),ssin=sin(t[k].f);
		t[k*2].f+=t[k].f;
		t[k*2+1].f+=t[k].f;
		t[k].f=0;
	    double x,y;
	    x=t[k*2].x*ccos-t[k*2].y*ssin;
	    y=t[k*2].x*ssin+t[k*2].y*ccos;
	    t[k*2].x=x;t[k*2].y=y;
	    
	    x=t[k*2+1].x*ccos-t[k*2+1].y*ssin;
	    y=t[k*2+1].x*ssin+t[k*2+1].y*ccos;
	    t[k*2+1].x=x;t[k*2+1].y=y;
	}
}
void build(int k,int l,int r){
	int mid=(l+r)/2;
	if (l==r){
		t[k].x=1.0;
		t[k].y=0.0;
		t[k].f=0;
		return;
	}
	build(k*2,l,mid);
	build(k*2+1,mid+1,r);
	updata(k);
}
void change(int k,int l,int r,int pos,double d){
	int mid=(l+r)/2;
	pushdown(k,l,r);
	if (l==r){
	    double len=dis(t[k].x,t[k].y);
	    double x=t[k].x/len*d,y=t[k].y/len*d;
	    t[k].x+=x;
	    t[k].y+=y;
	    return;
	}
	if (pos<=mid) change(k*2,l,mid,pos,d);
	else change(k*2+1,mid+1,r,pos,d);
	updata(k);
}
void turn_angle(int k,int l,int r,int x,int y,double d){
	pushdown(k,l,r);
	if (l==x&&y==r){
		double ccos=cos(d),ssin=sin(d);
		double x,y;
	    x=t[k].x*ccos-t[k].y*ssin;
	    y=t[k].x*ssin+t[k].y*ccos;
	    t[k].x=x;t[k].y=y;
	    t[k].f+=d;
	    pushdown(k,l,r);
	    return;
	}
	int mid=(l+r)/2;
	if (y<=mid) turn_angle(k*2,l,mid,x,y,d);
	else
	if (x>=mid+1) turn_angle(k*2+1,mid+1,r,x,y,d);
	else{
		turn_angle(k*2,l,mid,x,mid,d);
		turn_angle(k*2+1,mid+1,r,mid+1,y,d);
	}
	updata(k);
}
int main(){
	scanf("%d%d",&n,&m);
	build(1,1,n);
	for (int i=1;i<=m;i++){
		scanf("%d",&opt);
		if (opt==1){
			scanf("%d%lf",&pos,&d);
			change(1,1,n,pos,d);
			printf("%.12f %.12f\n",t[1].x,t[1].y);
		}
		else{
			scanf("%d%lf",&pos,&d);
			d=d/(180.0)*acos(-1);
			d=-d;
			turn_angle(1,1,n,pos,n,d);
			printf("%.12f %.12f\n",t[1].x,t[1].y);
		}
	}
}
  • Vote: I like it
  • -18
  • Vote: I do not like it