POJ_2991
如果我们将其中某一个线段旋转β角,那么这个线段上方的所有线段都会旋转β角,这就很类似线段树中的对区间加上一个常数的问题了,于是不妨向着线段树的思路去想。
接下来一个问题就是β角是相对于谁的,换句话说我们所谓的每个线段都会旋转β角,那么是绕谁旋转的?实际上,如果我们局限于把线段当线段看的话,那么这个旋转就会看成是绕某个定点的,这个点就是我们旋转的线段和它下面那个不动的线段的交点,再这样想下去我们就没法处理了,因为每个旋转操作所绕的定点不是唯一的,我们没办法把所有的旋转操作都统一到一起,那么我们就没办法把旋转操作叠加,这样就没法使用线段树了。
但如果换个思路的话,实际上β角还等于这个线段旋转后所在的直线和未旋转前所在的直线的夹角,而直线的夹角是可以用向量的夹角表示的,如果我们把线段看成一个向量的话那么β角就是这个向量旋转的角度。如果这么看的话,所有的旋转操作就可以统一到一起了,也可以叠加了,因为这样不会局限于绕哪个定点,只需要把向量自身旋转一下就OK。其实说到这里,我们会发现其实上一段的分析从一开始就误入歧途了,我们着眼于了“β角是相对于谁的”,因为相对的东西是不可能统一到一起的,参考系不一样结果就不一样,所以我们要想把每个线段的旋转操作统一到一起,就要去看这些旋转操作改变了哪些绝对的量,而向量就是一个绝对的量,它并不参考与其他的东西,只由这个线段自身的状态决定。
又扯远了,还是分析下怎么实现吧。前面说了,如果把线段看成向量的话,我们每次的旋转操作就可以看成是对区间上的所有点加上一个值(向量的旋转角),那么剩下的问题有两个:第一,也是最重要的,我们这样记录能不能每次方便地求出终点的位置?第二,题目中给出的是每次设定的两个线段的夹角,我们能不能方便的将其转化成相对于以前的状态旋转了多少角度?
对于第一个问题,我们既然有了每个线段的向量,那么我们只要把这些向量求和,最终所指的位置就是终点,因此我们只要维护好向量的区间和就可以了。对于第二个问题,我们可以用一个数组degree[i]表示第i个向量和第i-1一个向量当前的夹角,这样就有了当前的状态,每次读入操作后就会方便的得到相当于进行旋转多少角度的操作了,然后再更新一下degree[i]即可。并且我们每读入一个操作只会影响一个degree[]的值,不会影响到其他的degree[]。
总而言之,我们要把每个线段看成一个向量,并维护这些向量的区间和,同时要实现对区间中每个元素都加上一个值这一操作。
#include#include #include #define MAXD 10010 const double PI = acos(-1.0); int N, M, a[MAXD], A[MAXD], degree[MAXD], rd[4 * MAXD]; struct point { double x, y; }dp[4 * MAXD]; double getrad(int x) { return x * PI / 180; } void build(int cur, int x, int y) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; rd[cur] = 0; dp[cur].x = 0, dp[cur].y = A[y] - A[x - 1]; if(x == y) return ; build(ls, x, mid); build(rs, mid + 1, y); } void init() { int i; A[0] = 0; for(i = 1; i <= N; i ++) { scanf("%d", &a[i]); A[i] = A[i - 1] + a[i]; degree[i] = 0; } build(1, 1, N); } void update(int cur) { int ls = cur << 1, rs = (cur << 1) | 1; dp[cur].x = dp[ls].x + dp[rs].x, dp[cur].y = dp[ls].y + dp[rs].y; } void Rotate(double &dx, double &dy, double rad) { double x = dx, y = dy; dx = x * cos(rad) - y * sin(rad); dy = x * sin(rad) + y * cos(rad); } void pushdown(int cur) { int ls = cur << 1, rs = (cur << 1) | 1; if(rd[cur]) { double rad = getrad(rd[cur]); rd[ls] += rd[cur], rd[rs] += rd[cur]; Rotate(dp[ls].x, dp[ls].y, rad); Rotate(dp[rs].x, dp[rs].y, rad); rd[cur] = 0; } } void refresh(int cur, int x, int y, int k, int delta) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; if(x == y) { double rad = getrad(delta); Rotate(dp[cur].x, dp[cur].y, rad); return ; } pushdown(cur); if(mid + 1 < k) refresh(rs, mid + 1, y, k, delta); else { double rad = getrad(delta); if(k <= mid) refresh(ls, x, mid, k, delta); Rotate(dp[rs].x, dp[rs].y, rad); rd[rs] += delta; } update(cur); } void solve() { int i, j, k, d, delta; for(i = 0; i < M; i ++) { scanf("%d%d", &k, &d); ++ k, d = d - 180; delta = d - degree[k]; degree[k] = d; refresh(1, 1, N, k, delta); printf("%.2f %.2f\n", dp[1].x, dp[1].y); } } int main() { int t = 0; while(scanf("%d%d", &N, &M) == 2) { init(); if(t ++) printf("\n"); solve(); } return 0; }