poj2991 Crane 线段树

poj2991

学习的题解

在挑战程序设计竞赛(大白)上想弄懂树状数组,然后发现它先讲线段树,于是就先学线段树,于是就这道题卡了两个晚上。

首先是线段树的结构,一看书大致想起来一点。这里写的时候,就是一点,数组要开得够大,4倍的数据量才够。

这道题以线段树为载体,还承载了一个向量旋转的重要方法。一开始直接看题解、大白的式子一脸懵逼,然后看了题解上知道了它的rad值的含义以后,画个图,就能用两角差展开式推导出来,(x,y)的向量顺时针旋转α角度后得到的新坐标(x0,y0)可以用x,y,α表示。

极其难受的是,第二个晚上调试过程中 ,一直和题解一行行对照,最后猛然发现把update函数命名覆盖以后就可以跑出结果,然后锁定是double rad误申明成int rad的原因。很好,以后查低级bug又多了一个数据类型匹配的审查点。

上代码。其实已经改得和题解几乎一样了。但是有自己的一些注释,是不一样的可以起提醒作用的东西。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define lson l,mid,rt<<1
#define rson mid,r,rt<<1|1
#define mx 10010

using namespace std;
struct ST
{
    double x,y,lazy;
} T[mx<<2];//开得大一些 直接乘4
const double PI=asin(1.0)*2;
void build(int l,int r,int rt)
{
    T[rt].x=T[rt].lazy=0.0;
    if(r-l==1)
    {
        scanf("%lf",&T[rt].y);
        return ;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    T[rt].y=T[rt<<1].y+T[rt<<1|1].y;
}
double pre[mx];
void update(int L,int R,double rad,int l,int r,int rt)//rad的类型设错一度让我崩溃
{
    double x,y;
    if(L==l && R==r)
    {
        x=T[rt].x*cos(rad) + T[rt].y*sin(rad);
        y=T[rt].y*cos(rad) - T[rt].x*sin(rad);
        T[rt].x=x;T[rt].y=y;//把这部分整体旋转过来
        T[rt].lazy+=rad;//记得lazy值是相加的
        return ;
    }
    int mid=(l+r)>>1;
    if(T[rt].lazy)//让这个区间的左右孩子分别旋转
    {
        x=T[rt<<1].x*cos(T[rt].lazy) + T[rt<<1].y*sin(T[rt].lazy);
        y=T[rt<<1].y*cos(T[rt].lazy) - T[rt<<1].x*sin(T[rt].lazy);
        T[rt<<1].x=x,T[rt<<1].y=y;
        T[rt<<1].lazy+=T[rt].lazy;

        x=T[rt<<1|1].x*cos(T[rt].lazy) + T[rt<<1|1].y*sin(T[rt].lazy);
        y=T[rt<<1|1].y*cos(T[rt].lazy) - T[rt<<1|1].x*sin(T[rt].lazy);
        T[rt<<1|1].x=x,T[rt<<1|1].y=y;
        T[rt<<1|1].lazy+=T[rt].lazy;//要记得把lazy值下放
        T[rt].lazy=0.;
    }
    if(L>=mid) update(L,R,rad,rson);
    else if(R<=mid) update(L,R,rad,lson);
    else
    {
        update(L,mid,rad,lson);
        update(mid,R,rad,rson);
    }
    T[rt].x=T[rt<<1].x+T[rt<<1|1].x;
    T[rt].y=T[rt<<1].y+T[rt<<1|1].y;
}
int main()
{
    int n,c;
    while(~scanf("%d%d",&n,&c))
    {
        build(0,n,1);
        for(int i=1; i<=n; i++)
            pre[i]=PI;
        while(c--)
        {
            int s,a;
            scanf("%d%d",&s,&a);
            double rad=a/180. * PI;
            update(s,n,pre[s]-rad,0,n,1);
            pre[s]=rad;
            printf("%.2lf %.2lf\n",T[1].x,T[1].y);
        }
        cout<<endl;
    }
    return 0;
}

另外吐槽一句poj是真的难受,万能头文件不能用,asin(1.)都过不了,非得写成asin(1.0),当时情况就是懵逼树上懵逼果,懵逼树下poj和我。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值