POJ2991 Crane(线段树成段更新+向量旋转)

来源:互联网 发布:淘宝如何上传照片 编辑:程序博客网 时间:2024/06/09 18:41

DescriptionACM 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. InputThe input consists of several instances, separated by single empty lines. The first line of each instance consists of two integers 1 ≤ n ≤10 000 and c 0 separated by a single space -- the number of segments of the crane and the number of commands. The second line consists of n integers l1,..., ln (1 li 100) separated by single spaces. The length of the i-th segment of the crane is li. The following c lines specify the commands of the operator. Each line describing the command consists of two integers s and a (1 ≤ s < n, 0 ≤ a ≤ 359) separated by a single space -- the order to change the angle between the s-th and the s + 1-th segment to a degrees (the angle is measured counterclockwise from the s-th to the s + 1-th segment).OutputThe output for each instance consists of c lines. The i-th of the lines consists of two rational numbers x and y separated by a single space -- the coordinates of the end of the n-th segment after the i-th command, rounded to two digits after the decimal point. The outputs for each two consecutive instances must be separated by a single empty line.Sample Input2 110 51 903 25 5 51 2702 90Sample Output5.00 10.00-10.00 5.00-5.00 10.00SourceCTU Open 2005
这道题呢,涉及的是线段树的成段更新,这里我们更新的每一段的坐标,由于我们求的是最后一段顶点的坐标,所以我们只需要把所有段的顶点的坐标加起来就是最终的答案。
我们这里用的是向量,那么来了,向量的旋转坐标是怎么变化的呢,这里涉及的是一些数学知识,看下图。

这里写图片描述

所以呢,向量的坐标变化为:Vx=cosA*x-sinA*yVy=cosA*y+sinA*x
接下来就是手写线段树了,就加了一个懒惰标记,成段跟新[q+1,N]这一大段中所有小段的坐标,q+1,q+2,...,N.由于我们求的是最后一段的点的坐标,所以我们只需要把[1,N]每一段的坐标加起来就可以了(可能这里会疑问,怎么可以全部加起来呢,那一定坐标变大了,其实,前面说过,我们更新的每一段的坐标,这些坐标都对应某一段的起点(0,0),旋转后的坐标也是相对的,有正有负,所以,最后加起来,一定是最顶点的左边,即sum[1]).大概就这些。ps:这里给的角度是改变后所处的角度,所以我们还需要算出旋转之后的角度。(英语好真的很重要,题都读不懂gg)
#include<iostream>#include<cstring>#include<cstdlib>#include<algorithm>#include<cctype>#include<cmath>#include<ctime>#include<string>#include<stack>#include<deque>#include<queue>#include<list>#include<set>#include<map>#include<cstdio>#include<limits.h>#define MOD 1000000007#define fir first#define sec second#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)#define mes(x, m) memset(x, m, sizeof(x))#define Pii pair<int, int>#define Pll pair<ll, ll>#define INF 1e9+7#define Pi 4.0*atan(1.0)#define lowbit(x) (x&(-x))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1typedef long long ll;typedef unsigned long long ull;const double eps = 1e-12;const int maxn = 10010;using namespace std;inline int read(){    int x(0),op(1);    char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')op=-1,ch=getchar();}    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();    return x*op;}//Xi=cosx-siny//Yi=sinx+cosydouble sum[maxn<<2]; //坐标double re[maxn<<2]; //懒惰标记double pre[maxn]; //各段当前的角度double x[maxn<<2]; double y[maxn<<2];double Change(double ang) //角度转弧度{    double res=ang/180*Pi;    return res;}inline void work(double ang,int rt) {    if(ang>=360){  //控制在360以内,其实也可以不用        ang=(int)ang%360;    }    double res=Change(ang);    double vx=x[rt];    double vy=y[rt];    x[rt]=cos(res)*vx-sin(res)*vy; //向量旋转的坐标变化    y[rt]=cos(res)*vy+sin(res)*vx;  //}inline void PushUp(int rt){    x[rt]=x[rt<<1]+x[rt<<1|1];    y[rt]=y[rt<<1]+y[rt<<1|1];}inline void PushDown(int rt){    if(re[rt]){        work(re[rt],rt<<1);        work(re[rt],rt<<1|1);        re[rt<<1]+=re[rt];        re[rt<<1|1]+=re[rt];        re[rt]=0;    }}inline void buildTree(int l,int r,int rt){    re[rt]=0,x[rt]=0; //初始化    if(l==r){        scanf("%lf",&y[rt]);        return;    }    int m=(l+r)>>1;    buildTree(lson);    buildTree(rson);    PushUp(rt);}inline void update(double ang,int L,int R,int l,int r,int rt){    if(L<=l&&r<=R){        re[rt]+=ang;        work(ang,rt);         return;    }    PushDown(rt);    int m=(l+r)>>1;    if(L<=m){        update(ang,L,R,lson);    }    if(R>m){        update(ang,L,R,rson);    }    PushUp(rt);}int main(){    //fin;    int N,C;    double ang,tmp;    int lenCount;    bool flag=false;    while(~scanf("%d%d",&N,&C)){        if(flag){            cout<<endl;        }        flag=true;        buildTree(1,N,1);        for(int i=1;i<=N;++i){ //初始状态,180度            pre[i]=180;        }        while(C--){            scanf("%d%lf",&lenCount,&ang);            tmp=ang-pre[lenCount+1]; //算出旋转的角度,注意从逆时针开始            pre[lenCount+1]=ang;            update(tmp,lenCount+1,N,1,N,1);            printf("%.2f %.2f\n",x[1],y[1]);//这里怎么说,%.2lf g++超时,c++就不会,而%.2f就没事        }    }    return 0;}
0 0
原创粉丝点击