POJ 2991 Crane (线段树 维护旋转的向量和)

题目大意:

就是多个木棍初始摆在y轴上相邻的木棍间有连接着他们的东西, 相当于关节

然后每次操作旋转某个关节, 求旋转后的端点的坐标


大致思路:

首先将所有的木棍拆成多个向量, 那么考虑到向量的和v1 + v2 + ... + vk即为顶点的坐标, 并且多个向量的和旋转得到的角, 和这所有的向量都旋转同样的角再求和得到的向量是同样的

也就是说向量的旋转的时机不影响加法运算于是可以用线段树维护一个向量的数组, 每次区间更新, 利用懒惰标记, 然后逆时针旋转的话有旋转的公式可以很快确定

对于每次询问直接求所有向量的和就可以了, 总体复杂度O(nlogn)


代码如下:

Result  :  Accepted     Memory  :  1168 KB    Time  :  844 ms

/*
 * Author: Gatevin
 * Created Time:  2015/8/17 22:49:05
 * File Name: Sakura_Chiyo.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

#define maxn 10010

int n, len[maxn];
const double PI = acos(-1.0);

struct Segment_Tree
{
    #define lson l, mid, rt << 1
    #define rson mid + 1, r, rt << 1 | 1
    pair<double, double> p[maxn << 2];//向量
    double theta[maxn << 2];
    void pushUp(int rt)
    {
        p[rt].first = p[rt << 1].first + p[rt << 1 | 1].first;
        p[rt].second = p[rt << 1].second + p[rt << 1 | 1].second;
        return;
    }
    void pushDown(int rt)
    {
        if(theta[rt])
        {
            theta[rt << 1] += theta[rt];
            theta[rt << 1 | 1] += theta[rt];
            p[rt << 1] = make_pair(p[rt << 1].first*cos(theta[rt]) - p[rt << 1].second*sin(theta[rt]),
                                   p[rt << 1].first*sin(theta[rt]) + p[rt << 1].second*cos(theta[rt]));
            p[rt << 1 | 1] = make_pair(p[rt << 1 | 1].first*cos(theta[rt]) - p[rt << 1 | 1].second*sin(theta[rt]),
                                       p[rt << 1 | 1].first*sin(theta[rt]) + p[rt << 1 | 1].second*cos(theta[rt]));
            theta[rt] = 0;
        }
        return;
    }
    void build(int l, int r, int rt)
    {
        theta[rt] = 0;//逆时针方向需要的旋转角
        if(l == r)
        {
            p[rt] = make_pair(0., len[l]*1.);
            return;
        }
        int mid = (l + r) >> 1;
        build(lson);
        build(rson);
        pushUp(rt);
    }
    void update(int l, int r, int rt, int L, int R, double angle)//逆时针多旋转angle
    {
        if(l >= L && r <= R)
        {
            theta[rt] += angle;
            p[rt] = make_pair(p[rt].first*cos(angle) - p[rt].second*sin(angle),
                              p[rt].first*sin(angle) + p[rt].second*cos(angle));
            return;
        }
        int mid = (l + r) >> 1;
        pushDown(rt);
        if(mid >= L) update(lson, L, R, angle);
        if(mid + 1 <= R) update(rson, L, R, angle);
        pushUp(rt);
    }
    pair<double, double> query(int l, int r, int rt, int L, int R)
    {
        if(l >= L && r <= R)
            return p[rt];
        int mid = (l + r) >> 1;
        pushDown(rt);
        pair<double, double> ret = make_pair(0., 0.);
        pair<double, double> tmp;
        if(mid >= L)
        {
            tmp = query(lson, L, R);
            ret.first += tmp.first, ret.second += tmp.second;
        }
        if(mid + 1 <= R)
        {
            tmp = query(rson, L, R);
            ret.first += tmp.first, ret.second += tmp.second;
        }
        return ret;
    }
};

Segment_Tree ST;
double angle[maxn];

int main()
{
    int n, Q;
    while(~scanf("%d %d", &n, &Q))
    {
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &len[i]);
            angle[i] = PI;
        }
        ST.build(1, n, 1);
        int p, an;
        for(int i = 1; i <= Q; i++)
        {
            scanf("%d %d", &p, &an);
            double change = an/180.*PI - angle[p];
            angle[p] = an/180.*PI;
            ST.update(1, n, 1, p + 1, n, change);
            pair<double, double> ans = ST.query(1, n, 1, 1, n);
            printf("%.2f %.2f\n", ans.first, ans.second);
        }
    }
    return 0;
}


你可能感兴趣的:(线段树,poj,Crane,向量和,2991)