题目链接:http://poj.org/problem?id=2991
题目意思:这是一个n结棍,现在沿y轴放置,从(0,l1)为第0条边,(l1, l2)为第1条边……(l(n-1),l(n))为第n-1条边,操作说明,把第k条边沿顺时针方向旋转a度(第k+1……n跟着第k条边一起旋转),问题:求每次操作以后这个n结棍的末端的坐标
算法:线段树,三角运算
思路:把n结棍每节的长度保存在每个线段树的节点上,如果k旋转a度,那么把(k,n)每个节点全部都加上一个角度,通过三角运算得到这个节点(线段)沿x轴,沿y轴的长度,统计每个节点(线段)的数据,把它汇总到root节点,就可以得到n结棍末端的坐标了。
#include"cstdio"
#include"cstring"
#include"math.h"
using namespace std;
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
#define mid int m = (r+l) >> 1
double sx[234567 << 2];
double sy[223232 << 2];
int sd[232323 << 2];
int angle[232323 << 2];
void PushUp(int rt)
{
sx[rt] = sx[rt << 1 ] + sx[rt << 1|1 ];
sy[rt] = sy[rt << 1 ] + sy[rt << 1|1 ];
}
void build(int l, int r, int rt)
{
sd[rt] = 0;
if(l == r)
{
scanf("%lf", &sy[rt]);
sx[rt] = 0;
return ;
}
mid ;
build(lson);
build(rson);
PushUp(rt);
}
void ff(int rt, int sd)
{
double dd = (sd) * asin(1.0) / 90;
double x = sx[rt] * cos(dd) - sy[rt] * sin(dd);
double y = sx[rt] * sin(dd) + sy[rt] * cos(dd);
sx[rt] = x;
sy[rt] = y;
}
void PushDown(int rt)
{
if(sd[rt] != 0)
{
ff(rt << 1, sd[rt]);
ff(rt << 1 | 1, sd[rt]);
sd[rt << 1] += sd[rt] ; sd[rt << 1 | 1] += sd[rt];
sd[rt] = 0;
}
}
void update(int a, int ang, int l, int r, int rt)
{
if(a < l)
{
ff(rt, ang);
sd[rt] += ang;
return ;
}
mid ;
PushDown(rt);
if(a < m)
update(a, ang, lson);
update(a, ang, rson);
PushUp(rt);
}
int main()
{
int n, m;
int first =1;
while(scanf("%d%d", &n, &m) != EOF)
{
if(first)
first = 0;
else
printf("\n");
int i;
for(i = 1; i <= n; i ++)
angle[i] = 180;
build(1, n, 1);
for(i = 1; i <= m; i ++)
{
int a, b;
scanf("%d%d", &a, &b);
update(a, b-angle[a], 1, n, 1);
angle[a] = b;
printf("%.2lf %.2lf\n",fabs(sx[1])<1e-8?0:sx[1],fabs(sy[1])<1e-8?0:sy[1]);
}
}
return 0;
}