每个叶子节点保存每个线段的向量。
那么答案就是线段树区间和。
每次操作就是对向量进行旋转,线段树的区间更新加上向量旋转公式搞定。
设有向量(x0,y0),逆时针旋转A度后的向量为(x1,y1),有
x1=x0 * cos(A)- y0 * sin(A)
y1=x0 * sin(A)+ y0 * cos(A)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define M_PI 3.14159265358979323846
const int MAXN=10000,MAXC=10000;
int N,C,S[MAXC+10];
double A[MAXC+10],L[MAXN+10];
double VX[MAXN<<2],VY[MAXN<<2];
double Ang[MAXN<<2];
double pre[MAXN+10];
void pushup(int rt){
VX[rt]=VX[rt<<1]+VX[rt<<1|1];
VY[rt]=VY[rt<<1]+VY[rt<<1|1];
}
void pushdown(int rt){
if(Ang[rt]){
double ang=Ang[rt],vx=VX[rt<<1],vy=VY[rt<<1];
Ang[rt<<1]+=Ang[rt];
VX[rt<<1]=vx*cos(-ang)-vy*sin(-ang),VY[rt<<1]=vx*sin(-ang)+vy*cos(-ang);
ang=Ang[rt],vx=VX[rt<<1|1],vy=VY[rt<<1|1];
Ang[rt<<1|1]+=Ang[rt];
VX[rt<<1|1]=vx*cos(-ang)-vy*sin(-ang),VY[rt<<1|1]=vx*sin(-ang)+vy*cos(-ang);
Ang[rt]=0;
}
}
void build(int l,int r,int rt){
Ang[rt]=0;
if(l==r){
VX[rt]=0; VY[rt]=L[l];
return;
}
int m=((l+r)>>1);
build(lson);
build(rson);
pushup(rt);
}
void updata(int L,int R,double val,int l,int r,int rt){
if(L<=l&&r<=R){
double ang=val,vx=VX[rt],vy=VY[rt];
Ang[rt]+=val;
VX[rt]=vx*cos(-ang)-vy*sin(-ang),VY[rt]=vx*sin(-ang)+vy*cos(-ang);
return;
}
pushdown(rt);
int m=((l+r)>>1);
if(L<=m) updata(L,R,val,lson);
if(R>m) updata(L,R,val,rson);
pushup(rt);
}
int main(){
bool first=1;
while(~scanf("%d%d",&N,&C)){
for(int i=0;i<N;i++){
scanf("%lf",&L[i]);
}
if(!first) printf("\n");
first=0;
fill(pre,pre+N,180.0);
build(0,N-1,1);
for(int i=0;i<C;i++){
scanf("%d%lf",&S[i],&A[i]);
double val=((pre[S[i]]-A[i])*2*M_PI)/360.0;
pre[S[i]]=A[i];
updata(S[i],N-1,val,0,N-1,1);
printf("%.2f %.2f\n",VX[1],VY[1]);
}
}
return 0;
}