思路就是按照白皮书上走得,不过代码没有按照白皮书的写,一些关键点直接看代码吧。
学到的公式:向量 以任意(x0,y0)顺时针旋转a角度后新向量
x’=(x-x0)*cos(a)-(y-y0)*sin(a)+x0
y’=(x-x0)*sin(a)+(y-y0)*cos(a)+y0
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const long long INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int, int> pir;
int n, co;
double yi[4*10005];
double xi[4*10005];
double d[4*10005];
double degree[4*10005];
double a;
int s;
void pushup(int rt) //向上跟新节点,即回溯父节点
{
xi[rt] = xi[rt << 1] + xi[rt << 1 | 1];
yi[rt] = yi[rt << 1] + yi[rt << 1 | 1];
}
void build(int l, int r,int rt)//建树
{
d[rt] = 0;//lazy标记。
if (l == r)//左右相等的时候,即叶子节点
{
scanf("%lf", &yi[rt]);
xi[rt] = 0;//初始x轴方向一直为零
return;
}
int mid = (l + r) >> 1;
build(l, mid, rt << 1);
build(mid + 1, r, rt << 1 | 1);
pushup(rt);//先递归建树,再更新父节点依次
}
void rotate(int rt, double a)//旋转
{
double rad = pi * a / 180.0;
double nx = xi[rt] * cos(rad) - yi[rt] * sin(rad);
double ny = xi[rt] * sin(rad) + yi[rt] * cos(rad);//向量更新公式
xi[rt] = nx;
yi[rt] = ny;
}
void pushdown(int rt)//往自己的左右节点更新,即向下更新
{
if (d[rt])//如果有标记的话,因为这里我们每一次旋转了过后,值更新了父节点并没有将该节点
//的子节点更新,因为这样太慢了,只有要用到的时候,在更新
{
d[rt * 2] += d[rt];
d[rt<< 1 | 1] += d[rt];
rotate(rt<<1, d[rt]);
rotate(rt << 1 | 1, d[rt]);
d[rt] = 0;//清楚标记
}
}
void solve(int i,int l,int r,double a,int rt)//树的主要函数
{
if (i <= l)//如果s+1在整个区间的左边了,肯定全部更新
{
rotate(rt,a);
d[rt] += a;
return;//这里要return,不继续更新子节点,就是lazy标记的作用了,用到再更新
}
pushdown(rt);//每一个根节点都要向下更新试试,看是否标记了。
int mid = (r + l) >> 1;
if (i <= mid)solve(i, l, mid, a, rt << 1);//注意等号
solve(i, mid + 1, r, a, rt << 1 | 1);//无论如何右边是要更新的,因为i如果<=mid,那么
//右边节点递归过去就相当于s+1在整个右边节点,需要整体旋转,如果i>mid那么更要更新右边了
pushup(rt);//回溯父节点
}
int main()
{
int flag = 0;
while (cin >> n >> co)
{
if (flag++)puts("");//控制一下输出格式
build(1, n, 1);
upd(i, 0, n)degree[i] = 180;
up(i, 0, co)
{
cin >> s >> a;
solve(s + 1, 1, n, a - degree[s], 1);//第s+1跟旋转
//这里我全部用的左闭右闭区间
degree[s] = a;//每次更新与y轴的角度
printf("%.2f %.2f\n", xi[1], yi[1]);
}
}
return 0;
}
//我这个似乎1600ms了,应该可能有些地方做的不够好,看看还能不能继续优化了