E. Robot Arm

题目连接:

http://www.codeforces.com/contest/618/problem/E

Description

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.

Sample Input

5 4

1 1 3

2 3 90

2 5 48

1 4 1

Sample Output

8.0000000000 0.0000000000

5.0000000000 -3.0000000000

4.2568551745 -2.6691306064

4.2568551745 -3.6691306064

Hint

题意

有一个机械臂,这个机械臂上面有n个点,i个点和i+1个点通过一条线段相连接

有两个操作:

1 x y,将第x个线段伸长y米

2 x y,将x个线段绕着上一个线段顺时针旋转y°

然后每次询问之后,问你最后那个点的位置在哪儿

题解:

线段树

我们在线段树的每个叶子节点,维护当前这个线段较上一个线段的角度,和当前线段端点的坐标

修改很简单,直接暴力修改这个叶子节点就好了

push_up的时候,就是把两个线段融合成一个线段

这个大概是个初中数学,大概画一画就出来了吧(误

总之就是这样

还有一种做法是矩阵,旋转和延长,其实都是矩阵变换

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5+7;
const double pi = acos(-1.0);
typedef double SgTreeDataType;
struct treenode
{
int L , R ;
SgTreeDataType x,y,ang;
}; treenode tree[maxn*4]; inline void push_down(int o)
{ } inline void push_up(int o)
{
tree[o].x = tree[o*2].x+tree[o*2+1].x*cos(tree[o*2].ang)-tree[o*2+1].y*sin(tree[o*2].ang);
tree[o].y = tree[o*2].y+tree[o*2+1].x*sin(tree[o*2].ang)+tree[o*2+1].y*cos(tree[o*2].ang);
tree[o].ang = tree[o*2].ang+tree[o*2+1].ang;
} inline void build_tree(int L , int R , int o)
{
tree[o].L = L , tree[o].R = R;
if (L == R)
{
tree[o].x = 1;
tree[o].y = 0;
tree[o].ang = 0;
return;
}
if (R > L)
{
int mid = (L+R) >> 1;
build_tree(L,mid,o*2);
build_tree(mid+1,R,o*2+1);
push_up(o);
}
} inline void update1(int QL,int QR,SgTreeDataType v,int o)
{
int L = tree[o].L , R = tree[o].R;
if (QL <= L && R <= QR)
{
tree[o].x += v * cos(tree[o].ang);
tree[o].y += v * sin(tree[o].ang);
return;
}
else
{
push_down(o);
int mid = (L+R)>>1;
if (QL <= mid) update1(QL,QR,v,o*2);
if (QR > mid) update1(QL,QR,v,o*2+1);
push_up(o);
}
} inline void update2(int QL,int QR,SgTreeDataType v,int o)
{
int L = tree[o].L , R = tree[o].R;
if (QL <= L && R <= QR)
{
double l = sqrt((tree[o].x*tree[o].x)+(tree[o].y*tree[o].y));
tree[o].ang -= v*pi/180.0;
tree[o].x = l * cos(tree[o].ang);
tree[o].y = l * sin(tree[o].ang);
return;
}
else
{
push_down(o);
int mid = (L+R)>>1;
if (QL <= mid) update2(QL,QR,v,o*2);
if (QR > mid) update2(QL,QR,v,o*2+1);
push_up(o);
}
} int main()
{
int n,m;
scanf("%d%d",&n,&m);
build_tree(1,n,1);
for(int i=1;i<=m;i++)
{
int op,x;
double y;
scanf("%d%d%lf",&op,&x,&y);
if(op==1)update1(x,x,y,1);
if(op==2)update2(x,x,y,1);
printf("%.12f %.12f\n",tree[1].x,tree[1].y);
}
return 0;
}

Wunder Fund Round 2016 (Div. 1 + Div. 2 combined) E. Robot Arm 线段树的更多相关文章

  1. Wunder Fund Round 2016 (Div. 1 + Div. 2 combined) B. Guess the Permutation 水题

    B. Guess the Permutation 题目连接: http://www.codeforces.com/contest/618/problem/B Description Bob has a ...

  2. Wunder Fund Round 2016 (Div. 1 + Div. 2 combined) A. Slime Combining 水题

    A. Slime Combining 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2768 Description Your frien ...

  3. Wunder Fund Round 2016 (Div. 1 + Div. 2 combined) F. Double Knapsack 鸽巢原理 构造

    F. Double Knapsack 题目连接: http://www.codeforces.com/contest/618/problem/F Description You are given t ...

  4. Wunder Fund Round 2016 (Div. 1 + Div. 2 combined)

    现在水平真的不够.只能够做做水题 A. Slime Combining 题意:就是给n个1给你.两个相同的数可以合并成一个数,比如说有两个相同的v,合并后的值就是v+1 思路:直接模拟栈 #inclu ...

  5. Codeforces Gym 101194G Pandaria (2016 ACM-ICPC EC-Final G题, 并查集 + 线段树合并)

    题目链接  2016 ACM-ICPC EC-Final Problem G 题意  给定一个无向图.每个点有一种颜色. 现在给定$q$个询问,每次询问$x$和$w$,求所有能通过边权值不超过$w$的 ...

  6. Codeforces Round #370 (Div. 2) E. Memory and Casinos (数学&&概率&&线段树)

    题目链接: http://codeforces.com/contest/712/problem/E 题目大意: 一条直线上有n格,在第i格有pi的可能性向右走一格,1-pi的可能性向左走一格,有2中操 ...

  7. Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum 离线+线段树

    题目链接: http://codeforces.com/contest/703/problem/D D. Mishka and Interesting sum time limit per test ...

  8. Codeforces Round #FF (Div. 2)__E. DZY Loves Fibonacci Numbers (CF447) 线段树

    http://codeforces.com/contest/447/problem/E 题意: 给定一个数组, m次操作, 1 l r 表示区间修改, 每次 a[i] +  Fibonacci[i-l ...

  9. Codeforces Round #538 (Div. 2) F 欧拉函数 + 区间修改线段树

    https://codeforces.com/contest/1114/problem/F 欧拉函数 + 区间更新线段树 题意 对一个序列(n<=4e5,a[i]<=300)两种操作: 1 ...

随机推荐

  1. Java回收方法区中回收的类

    回收的类必须满足下面三个条件才能算是“无用的类” 1.该类所有的实例都已经被回收,也就是说Java堆中不存在该类的任何实例: 2.加载该类的ClassLoader已经被回收: 3.该类对应的java. ...

  2. TCP之connect

    1. connect函数: #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *servaddr, ...

  3. CSS浮动和清除

    float:让元素浮动,取值:left(左浮动).right(右浮动) clear:清除浮动,取值:left(清除左浮动).right(清除右浮动).both(同时清除上面的左浮动和右浮动) 1.CS ...

  4. 给windows设置隐藏文件夹的方法

    cls @ECHO OFF title Folder Private if EXIST "HTG Locker" goto UNLOCK if NOT EXIST Private ...

  5. linux===启动sdk manager下载配置sdk的时候报错的解决办法

    当启动sdk manager下载配置sdk的时候,报错如下: botoo@botoo-virtual-machine:/opt/android-sdk-linux/tools$ sudo  ./and ...

  6. 【bzoj4459】JSOI2013丢番图

    某JSOI夏令营出题人啊,naive! 你还是得学习个,搬这种原题不得被我一眼看穿? 求个n^2的约数除以二,向上取整. #include<bits/stdc++.h> using nam ...

  7. MySQL的sql_mode解析与设置

    https://blog.csdn.net/hhq163/article/details/54140286 https://blog.csdn.net/ccccalculator/article/de ...

  8. 文字顺时针旋转90度(纵向)&古诗词排版

    1.文字旋转90度 width: 100px; height: 200px; line-height: 100px; text-align: center; writing-mode: vertica ...

  9. Mycat 读写分离

    简介 Mycat 是 MySQL中间件,Mycat的原理中最重要的一个动词就是'拦截',它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分片分析.路由分析.读写分离分析.缓存分 ...

  10. 算法入门系列1:k-means

    k-means是一种无监督学习算法,用于聚类. 下图(来自http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006910.html)展示了k-m ...