poj 2991 线段树 成段更新 + 向量旋转

题目链接:http://poj.org/problem?id=2991

输入数据:

n条线段,c条指令

n条线段的长度li(最初的线段都是在y轴上的)

c条的指令是s,a,表示第s条线段和第s+1条线段的夹角调整为a度

每执行完一条命令输出最后一条线段末尾的坐标


注意:输出的时候,c++中用%lf,g++中用%f。

keep[maxn]保存第i条边与i-1边的夹角(初始化为180°)

每次线段要旋转的角度由a-keep[s]得到(记得更新keep[s]=a)

向量公式

         t= a-keep[s];//t的正负不影响结果

         x1=x0*cos(t*PI/180) - y0*sin(t*PI/180);

 y1=y0*cos(t*PI/180) + x0*sin(t*PI/180);      

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
using namespace std;
 
const int maxn = 10010;
const double PI = acos(-1.0);//求出π的值
 
struct node
{
         intl;
         intr;
         doublex;
         doubley;
         intangle;
}tree[maxn*4];
int n,c;
int len[maxn];
int keep[maxn];
 
void turn(int p,int t)
{
         doublex0 = tree[p].x;
         doubley0 = tree[p].y;
         tree[p].x= x0*cos(t*PI/180) - y0*sin(t*PI/180);// sin,cos函数里面用的都是弧度,转换
         tree[p].y= y0*cos(t*PI/180) + x0*sin(t*PI/180);             
}
 
void create(int p,int l,int r)
{
         tree[p].l= l;
         tree[p].r= r;
         if(l== r)
         {
                   tree[p].x= 0;
                   tree[p].y= len[l];
                   return;
         }
         intmid = (l+r)>>1;
         create(p<<1,l,mid);
         create(p<<1|1,mid+1,r);
         tree[p].x= 0;
         tree[p].y= tree[p<<1].y + tree[p<<1|1].y;
         tree[p].angle= 0;
}
void pushdown(int p)
{
         if(tree[p].angle!= 0)
         {
                   turn(p<<1,tree[p].angle);
                   turn(p<<1|1,tree[p].angle);
                   tree[p<<1].angle+= tree[p].angle;
                   tree[p<<1|1].angle+= tree[p].angle;
                   tree[p].angle= 0;
         }
}
 
void update(int p, int l, int r, int TurnA)
{
         if(tree[p].l== l && tree[p].r == r)
         {
                   tree[p].angle+= TurnA;
                   turn(p,TurnA);
                   return;
         }
         pushdown(p);
         intmid = (tree[p].l+tree[p].r)>>1;
         if(r<= mid)
                   update(p<<1,l,r,TurnA);
         elseif(l > mid)
                   update(p<<1|1,l,r,TurnA);
                   else
                   {
                            update(p<<1,l,mid,TurnA);
                            update(p<<1|1,mid+1,r,TurnA);
                   }
         tree[p].x= tree[p<<1].x + tree[p<<1|1].x;
         tree[p].y= tree[p<<1].y + tree[p<<1|1].y;
}
 
int main()
{
         ints,a;
         intflag=0;
         while(~scanf("%d%d",&n,&c))
         {
                   if(flag)
                            printf("\n");
                   flag= 1;
                   for(inti = 1; i <= n; i++)
                   {
                            scanf("%d",&len[i]);//第i条边的长度
                            keep[i]= 180;//第i条边与前一条边的夹角
                   }
                   create(1,1,n);
 
                   for(inti = 0; i < c; i++)
                   {
                            scanf("%d%d",&s, &a);
                            s++;
                            update(1,s,n,a-keep[s]);
                            keep[s]= a;
                            printf("%.2lf%.2lf\n", tree[1].x, tree[1].y);
                   }                
         }
         return0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值