题意:
有一个吊车有很多段手臂,这些手臂都是相连着的,最开始每个手臂都垂直于x轴。
给出每个手臂的长度,和每次操作的手臂编号(从1 开始)以及每次操作把两个手臂在逆时针方向的夹角修改为多少度。
数据:
输入:
一个n 和一个c
n个 手臂分别的长度
c行 操作手臂编号 修改角度
输出:
每次操作后第n个手臂的末节点。
思路:
(一道题做三天也真是醉了。。。。,
最开始的思路是一个点相对另一个点旋转,求出每次的坐标,但是后来发现这么做无法和线段树的成段更新结合起来,因为每次操作都是是需要上次更新的节点信息,这样还需要先把上次的坐标算出来,所以其实复杂度就变成了O(c * k)
)
后来百度到的思路是这样的:
把所有的手臂都当成一个向量来操作,因为向量是绝对的,把相对坐标旋转的不确定性给避开了。
有两个好处。
1.尾节点的坐标就可以看成从第一个向量到最后一个向量的向量和。
2.进行旋转的时候,只需要旋转从修改节点下一个到最后节点的向量和就可以了。因为这个节点就代表了下面所有的向量的向量和,而每个向量旋转的角度都是相同的,向量和旋转的角度也是相同的, 并且,旋转的角度是可以累加计算的,从而可以和线段树成段更新的高效性结合在一起。
最后,送给自己一句话:省去现在必须付出的时间是愚蠢的行为,因为过后你需要用万倍的时间去弥补。
(就是因为不好好读题,一道题陷入误区1天,因为题意理解错了,又耽误两天)
Code:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<map>
#include<cctype>
#include<vector>
#define TEST
#define LL long long
#define Mt(f, x) memset(f, x, sizeof(f));
#define rep(i, s, e) for(int i = (s); i <= (e); ++i)
#ifdef TEST
#define See(a) cout << #a << " = " << a << endl;
#define See2(a, b) cout << #a << " = " << a << ' ' << #b << " = " << b << endl;
#define debug(a, s, e){ rep(_i, s, e) {cout << a[_i] << ' '; }cout << endl;}
#define debug2(a, s, e, ss, ee) rep(i_, s, e) {debug(a[i_], ss, ee);}
#else
#define See(a)
#define See2(a, b)
#define debug(a, s, e)
#define debug2(a, s, e, ss, ee)
#endif
const int MAX = 2e9;
const int MIN = -2e9;
const double PI = acos(-1.0);
const double eps = 1e-8;
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const int N = 10000 + 5;
double dx[N << 2], dy[N << 2];
int ang[N << 2], bef[N]; //记录每个向量旋转的角度,和每次手臂之间的夹角以计算每次的差量。
void rot(int rt, int rad) //计算旋转和的坐标
{
double d = rad / 180.0 * PI;
double x = dx[rt], y = dy[rt];
dx[rt] = x * cos(d) - y * sin(d);
dy[rt] = x * sin(d) + y * cos(d);
}
void pushUp(int rt)
{
dx[rt] = dx[rt << 1] + dx[rt << 1 | 1];
dy[rt] = dy[rt << 1] + dy[rt << 1 | 1];
}
void pushDown(int rt)
{
if(ang[rt])
{
rot(rt << 1, ang[rt]);
rot(rt << 1 | 1, ang[rt]);
ang[rt << 1] += ang[rt];
ang[rt << 1 | 1] += ang[rt];
ang[rt] = 0;
}
}
void build(int l, int r, int rt)
{
if(l == r)
{
dx[rt] = 0;
scanf("%lf", &dy[rt]);
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushUp(rt);
}
void update(int L, int R, int rad, int l, int r, int rt)
{
if(l >= L && r <= R)
{
rot(rt, rad);
ang[rt] += rad;
return ;
}
pushDown(rt);
int m = (l + r) >> 1;
if(L <= m)
{
update(L, R, rad, lson);
}
if(R > m)
{
update(L, R, rad, rson);
}
pushUp(rt);
}
int main()
{
int n, c;
bool first = true;
while(~scanf("%d%d", &n, &c))
{
printf(first ? "" : "\n");
first = false;
Mt(bef, 0);
Mt(ang, 0);
build(1, n, 1);
while(c--)
{
int b, d;
scanf("%d%d", &b, &d);
int rad = d - 180 - bef[b];//计算与上次角度的差量
bef[b] = d - 180; //更新角度
update(b + 1, n, rad, 1, n, 1);//更新从b + 1,到n 段的角度与坐标)
printf("%.2f %.2f\n", dx[1], dy[1]);
}
}
return 0;
}