zoukankan      html  css  js  c++  java
  • POJ 2991 Crane

    POJ_2991

        如果我们将其中某一个线段旋转β角,那么这个线段上方的所有线段都会旋转β角,这就很类似线段树中的对区间加上一个常数的问题了,于是不妨向着线段树的思路去想。

        接下来一个问题就是β角是相对于谁的,换句话说我们所谓的每个线段都会旋转β角,那么是绕谁旋转的?实际上,如果我们局限于把线段当线段看的话,那么这个旋转就会看成是绕某个定点的,这个点就是我们旋转的线段和它下面那个不动的线段的交点,再这样想下去我们就没法处理了,因为每个旋转操作所绕的定点不是唯一的,我们没办法把所有的旋转操作都统一到一起,那么我们就没办法把旋转操作叠加,这样就没法使用线段树了。

        但如果换个思路的话,实际上β角还等于这个线段旋转后所在的直线和未旋转前所在的直线的夹角,而直线的夹角是可以用向量的夹角表示的,如果我们把线段看成一个向量的话那么β角就是这个向量旋转的角度。如果这么看的话,所有的旋转操作就可以统一到一起了,也可以叠加了,因为这样不会局限于绕哪个定点,只需要把向量自身旋转一下就OK。其实说到这里,我们会发现其实上一段的分析从一开始就误入歧途了,我们着眼于了“β角是相对于谁的”,因为相对的东西是不可能统一到一起的,参考系不一样结果就不一样,所以我们要想把每个线段的旋转操作统一到一起,就要去看这些旋转操作改变了哪些绝对的量,而向量就是一个绝对的量,它并不参考与其他的东西,只由这个线段自身的状态决定。

        又扯远了,还是分析下怎么实现吧。前面说了,如果把线段看成向量的话,我们每次的旋转操作就可以看成是对区间上的所有点加上一个值(向量的旋转角),那么剩下的问题有两个:第一,也是最重要的,我们这样记录能不能每次方便地求出终点的位置?第二,题目中给出的是每次设定的两个线段的夹角,我们能不能方便的将其转化成相对于以前的状态旋转了多少角度?

        对于第一个问题,我们既然有了每个线段的向量,那么我们只要把这些向量求和,最终所指的位置就是终点,因此我们只要维护好向量的区间和就可以了。对于第二个问题,我们可以用一个数组degree[i]表示第i个向量和第i-1一个向量当前的夹角,这样就有了当前的状态,每次读入操作后就会方便的得到相当于进行旋转多少角度的操作了,然后再更新一下degree[i]即可。并且我们每读入一个操作只会影响一个degree[]的值,不会影响到其他的degree[]

        总而言之,我们要把每个线段看成一个向量,并维护这些向量的区间和,同时要实现对区间中每个元素都加上一个值这一操作。

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #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;
    }

     

  • 相关阅读:
    centos“You don't have permission to access /index.html on this server.”
    使用yum来安装或卸载CentOS图形界面包
    PHP上IIS上显示服务器应用程序不可用
    Windows 2003 远程桌面连接数超过最大连接数终极解决方案
    perl清理电脑上重复的文件
    wordpress在IIS6上首页访问不了
    WordPress首页出现循环重定向解决办法四则(转载)
    windows server 2003 如何在远程链接时更改用户密码
    Ubuntu下安装php5gd库,支持jpg、png、gif等格式图片处理
    wordpress设置用163邮箱账号发送邮件
  • 原文地址:https://www.cnblogs.com/staginner/p/2436436.html
Copyright © 2011-2022 走看看