很自然会想到是线段树,需要考虑维护什么信息。
我们需要的答案是从原点到末端的坐标,这个信息可以看出是多个向量相加,所以我们在子区间维护左端点到右端点的一个向量。
因为角度会发生改变,那么再维护一个左右区间之间的角度。那么父节点的向量就等于左孩子的向量加上右孩子旋转以后的向量。
对于修改si和si+1之间的角度,对于以上的信息,相当于si+1以后所有角度都增加了。因此只要修改增量就好了。
此外,线段树最大深度的科学估计方法:max_deep = ceil(log2(maxn))+1),而且2^(max_deep ) ≤4*maxn,是一个更紧的上界,对于主席树也适用。
#include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; #define para int o = 1, int l = 0,int r = n-1 #define lo (o<<1) #define ro (o<<1|1) #define TEMPvar int mid = (l+r)>>1, lc = lo, rc = ro; #define lsn lc, l, mid #define rsn rc, mid+1, r const int maxn = 1e4+5, ST_SIZE = 1<<15;//((int)ceil(log2(maxn))+1);//4*N , 0base -1 const double PI = acos(-1); double rad[ST_SIZE]; double vx[ST_SIZE], vy[ST_SIZE]; int L[maxn]; int n; double prv[maxn]; void build(para) { rad[o] = vx[o] = 0; if(r == l){ vy[o] = L[l]; } else { TEMPvar build(lsn); build(rsn); vy[o] = vy[lc] + vy[rc]; } } int qs; double qDrad; void update(para) { if(l < r){ TEMPvar if(qs<=mid) { update(lsn); rad[o] += qDrad; } else update(rsn); double s = sin(rad[o]), c = cos(rad[o]); vx[o] = vx[lc] + c*vx[rc] - s*vy[rc]; vy[o] = vy[lc] + s*vx[rc] + c*vy[rc]; } } //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif int C; bool firstCase = true; while(~scanf("%d%d",&n,&C)){ if(!firstCase) puts(""); else firstCase = false; for(int i = 0; i < n; i++) scanf("%d", L+i); fill(prv,prv+n-1,PI); build(); while(C--){ double ang; scanf("%d %lf", &qs, &ang); ang = ang/180*PI; qDrad = ang-prv[--qs]; update(); prv[qs] = ang; printf("%.2f %.2f ", vx[1], vy[1]); } } return 0; }