(中等) POJ 2991 Crane , 几何+线段树。

Description

  ACM has bought a new crane (crane -- je?áb) . The crane consists of n segments of various lengths, connected by flexible joints. The end of the i-th segment is joined to the beginning of the i + 1-th one, for 1 ≤ i < n. The beginning of the first segment is fixed at point with coordinates (0, 0) and its end at point with coordinates (0, w), where w is the length of the first segment. All of the segments lie always in one plane, and the joints allow arbitrary rotation in that plane. After series of unpleasant accidents, it was decided that software that controls the crane must contain a piece of code that constantly checks the position of the end of crane, and stops the crane if a collision should happen.

  Your task is to write a part of this software that determines the position of the end of the n-th segment after each command. The state of the crane is determined by the angles between consecutive segments. Initially, all of the angles are straight, i.e., 180o. The operator issues commands that change the angle in exactly one joint.

  题意就是一个挖掘机,饿。。。吊车,的机械臂,有n节,可以转动,问每次转动之后最后一个位置。

  刚开始的时候想到是用数组表示每一个点,然后用线段树更新某一个区间,但是超时了,因为每次更新都要让上一次更新全部更新彻底,其实就是直接全部更新,反而还不如直接模拟。后来看了看题解,提到向量。。。就是用数组记录区间内所有向量的和,那么所有区间的和就是答案,而且,每次旋转d度的话对这个区间也是旋转d度,没有区别。。。

  另外被这个题坑了两个小时,还是今年的头两个小时。。。建树的时候没有更新彻底,看来以后自己测试一定要多组数据。。。。

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>

#define lson L,M,po*2
#define rson M+1,R,po*2+1

using namespace std;

struct state
{
    double x,y;
};

const double PI=atan2(1.0,1.0)*4;

state BIT[10004*4];
int COL[10004*4];
int rang[10004];

void change(int po,int ct)
{
    double tang;
    double len;

    tang=atan2(BIT[po].y,BIT[po].x);
    len=sqrt(BIT[po].x*BIT[po].x+BIT[po].y*BIT[po].y);
    tang+=ct*PI/180.0;
    BIT[po].x=len*cos(tang);
    BIT[po].y=len*sin(tang);
}

void pushUP(int po)
{
    BIT[po].x=BIT[po*2].x+BIT[po*2+1].x;
    BIT[po].y=BIT[po*2].y+BIT[po*2+1].y;
}

void pushDown(int po)
{
    if(COL[po])
    {
        change(po*2,COL[po]);
        change(po*2+1,COL[po]);

        COL[po*2]+=COL[po];
        COL[po*2+1]+=COL[po];

        COL[po]=0;
    }
}

void build_tree(int L,int R,int po)
{
    COL[po]=0;                  //DON‘T FORGET !!!

    if(L==R)
    {
        int temp;

        BIT[po].x=0;
        COL[po]=0;
        scanf("%d",&temp);
        BIT[po].y=temp;

        return;
    }

    int M=(L+R)/2;

    build_tree(lson);
    build_tree(rson);

    pushUP(po);
}

void update(int ul,int ur,int ut,int L,int R,int po)
{
    if(ul<=L&&ur>=R)
    {
        change(po,ut);
        COL[po]+=ut;
        COL[po]%=360;
        return;
    }

    pushDown(po);

    int M=(L+R)/2;

    if(ul<=M)
        update(ul,ur,ut,lson);
    if(ur>M)
        update(ul,ur,ut,rson);

    pushUP(po);
}

int main()
{
    int n,c;
    int a,b;
    int cas=0;

    while(~scanf("%d %d",&n,&c))
    {
        if(cas++)
            printf("\n");

        build_tree(1,n,1);

        for(int i=1;i<=n;++i)
            rang[i]=0;

        for(int i=1;i<=c;++i)
        {
            scanf("%d %d",&a,&b);
            b-=180;
            if(b==-180)
                b=180;
            update(a+1,n,b-rang[a],1,n,1);
            rang[a]=b;

            printf("%.2lf %.2lf\n",BIT[1].x,BIT[1].y);
        }
    }

    return 0;
}

时间: 2024-08-03 08:58:53

(中等) POJ 2991 Crane , 几何+线段树。的相关文章

POJ - 2991 Crane (线段树+计算几何)

Description ACM has bought a new crane (crane -- je?áb) . The crane consists of n segments of various lengths, connected by flexible joints. The end of the i-th segment is joined to the beginning of the i + 1-th one, for 1 ≤ i < n. The beginning of t

POJ 2991 Crane(线段树+计算几何)

POJ 2991 Crane 题目链接 题意:给定一个垂直的挖掘机臂,有n段,现在每次操作可以旋转一个位置,把[s, s + 1]专程a度,每次旋转后要输出第n个位置的坐标 思路:线段树,把每一段当成一个向量,这样每一段的坐标就等于前几段的坐标和,然后每次旋转的时候,相当于把当前到最后位置全部加上一个角度,这样就需要区间修改了,然后每次还需要查询s,和s + 1当前的角度,所以需要单点查询,这样用线段树去维护即可 代码: #include <cstdio> #include <cstri

POJ 2991 Crane(线段树&#183;向量旋转)

题意  有一个Crane由n条线段连接组成  每个连接点处均可以任意旋转  给你n条线段的长度  然后又m次旋转操作  给你p和r  将第p和第p+1条线段之间的角度旋转为r  即第p条线段绕p的终点逆时针旋转r度后能够与第p+1条重合  问每次旋转后最后一条线段的终点坐标 可以发现  旋转第p+1条线段时  p+1后面的所有线段也一起旋转了  可以把Crane分解为n个向量  这些向量的和也就是Crane终点的坐标  用rad[i]保存第i个向量与第i+1个向量之间的夹角  每次旋转操作时  

poj 2991 Crane(线段树)

题目链接:poj 2991 Crane 题目大意:就是有一个机械手臂,有n结,给定每节的长度,一开始为垂直的.有m次操作,每次将x关节变成角度d,并且输出手臂末端的坐标. 解题思路:点的旋转公式(r为逆时针的角度): x′=x?cos(r)?y?sin(r) y′=x?sin(r)+y?cos(r) 没有做过类似的题目,线段树每个节点记录的为每节旋转的角度以及单节末端的位置.每次旋转新的角度,需要根据前一个节点的角度和当前节点的角度来计算(因为它不是再旋转d,而是变成角度d #include <

POJ 2991 Crane

二次联通门 : POJ 2991 Crane /* POJ 2991 Crane 线段树维护向量 对于每次修改操作 修改x的角度 就是修改x~N区间的所有向量 打个标记记录角度 当前向量的计算式子为 res为度数 x = tree[now].x * cos (res) - tree[now].y * sin (res); y = tree[now].x * sin (res) + tree[now].y * cos (res); 注意弧度制与角度值的互换 注意还要记录一下上次该向量的角度, 即a

Crane(线段树)

Description ACM has bought a new crane (crane -- je?áb) . The crane consists of n segments of various lengths, connected by flexible joints. The end of the i-th segment is joined to the beginning of the i + 1-th one, for 1 ≤ i < n. The beginning of t

POJ训练计划2777_Count Color(线段树/成段更新/区间染色)

解题报告 题意: 对线段染色,询问线段区间的颜色种数. 思路: 本来直接在线段树上染色,lz标记颜色.每次查询的话访问线段树,求出颜色种数.结果超时了,最坏的情况下,染色可以染到叶子节点. 换成存下区间的颜色种数,这样每次查询就不用找到叶子节点了,用按位或来处理颜色种数. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace

POJ训练计划1177_Picture(扫描线/线段树+离散)

解题报告 题意: 求矩形周长和. 思路: 左扫上扫,扫过了. #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; struct Seg { int lx,rx,ly,ry,h,v; friend bool operator < (Seg a,Seg b) { re

POJ训练计划2828_Buy Tickets(线段树/单点更新)

解题报告 题意: 插队完的顺序. 思路: 倒着处理数据,第i个人占据第j=pos[i]+1个的空位. 线段树维护区间空位信息. #include <iostream> #include <cstdio> #include <cstring> using namespace std; struct node { int x,v; } num[201000]; int sum[1000000],ans[201000]; void cbtree(int rt,int l,in