POJ2991

题目链接:https://vjudge.net/problem/POJ-2991

知识准备:

1、向量旋转公式:向量(x,y)逆时针旋转角度A,则旋转后的向量为(x*cos A-y*sin A, x*sin A+y*cos A).

详见:https://www.zybang.com/question/143ceaa20d3942f3c6dbe9415dd81d0a.html

2、PI可用这一行代码取得:

const double PI=acos(-1.0);

解题思路:思路来源于:http://www.cnblogs.com/staginner/archive/2012/04/07/2436436.html。

在此处 struct point pt[rt] 是rt对应的向量的坐标。

以结点间的向量为基础建立线段树。

第48行,if()里面的判断条件是个易错点,一开始没有把l-1,所以错了。

这是一道好题,值得重复做。

AC代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cmath>
 5 using namespace std;
 6 #define lson l,m,rt<<1
 7 #define rson m+1,r,rt<<1|1
 8 const int maxn=10000+3;
 9 const double PI=acos(-1.0);
10 int totlen[maxn],len[maxn],degree[maxn];
11 int rd[maxn<<2];
12 int n,c;
13 struct point{
14     double x,y;
15 }pt[maxn<<2];
16 double getrad(int a){
17     return (double)a/180*PI;
18 }
19 void Rotate(double &dx,double &dy,double rad){
20     double x=dx,y=dy;
21     dx=x*cos(rad)-y*sin(rad);
22     dy=x*sin(rad)+y*cos(rad);
23 }
24 void pushup(int rt){
25     pt[rt].x=pt[rt<<1].x+pt[rt<<1|1].x;
26     pt[rt].y=pt[rt<<1].y+pt[rt<<1|1].y;
27 }
28 void pushdown(int rt){
29     if(rd[rt]){
30         double rad=getrad(rd[rt]);
31         rd[rt<<1]+=rd[rt];
32         rd[rt<<1|1]+=rd[rt];
33         Rotate(pt[rt<<1].x,pt[rt<<1].y,rad);
34         Rotate(pt[rt<<1|1].x,pt[rt<<1|1].y,rad);
35         rd[rt]=0;
36     }
37 }
38 void build(int l,int r,int rt){
39     rd[rt]=0;
40     pt[rt].x=0;     pt[rt].y=totlen[r]-totlen[l-1];
41 //    printf("build: l = %d, r = %d, pt[%d].x = %lf, pt[%d].y = %lf\n",l,r,rt,pt[rt].x,rt,pt[rt].y);
42     if(l==r)    return;
43     int m=(l+r)>>1;
44     build(lson);
45     build(rson);
46 }
47 void update(int L,int R,int delta,int l,int r,int rt){
48     if(L<=l-1&&r<=R){
49         double rad=getrad(delta);
50         Rotate(pt[rt].x,pt[rt].y,rad);
51         rd[rt]+=delta;
52 //        printf("l = %d, r = %d, pt[%d].x = %lf,pt[%d].y = %lf\n",l,r,rt,pt[rt].x,rt,pt[rt].y);
53         return;
54     }
55     if(l==r)    return;
56     pushdown(rt);
57     int m=(l+r)>>1;
58     if(L<=m)    update(L,R,delta,lson);
59     if(m<R)     update(L,R,delta,rson);
60     pushup(rt);
61 }
62 int main(){
63
64     while(scanf("%d%d",&n,&c)==2){
65         int s,a;
66         for(int i=1;i<=n;i++){
67             scanf("%d",&len[i]);
68             totlen[i]=totlen[i-1]+len[i];
69         }
70         build(1,n,1);                  //_______________________
71         for(int i=0;i<=n;i++)   degree[i]=0;
72         while(c--){
73             scanf("%d%d",&s,&a);
74             a-=180;
75             int delta=a-degree[s];
76             degree[s]=a;
77             update(s,n,delta,1,n,1);
78             printf("%.2lf %.2lf\n",pt[1].x,pt[1].y);
79         }
80         printf("\n");
81     }
82     return 0;
83 }

时间: 2025-01-03 18:39:54

POJ2991的相关文章

poj2991 Crane(线段树)

Description ACM has bought a new crane (crane -- je?áb) . The crane consists of n segments of various lengths, connected by flexible joints. The end of the i-th segment is joined to the beginning of the i + 1-th one, for 1 ≤ i < n. The beginning of t

POJ2991 Crane 【线段树+计算几何】

Crane Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3777   Accepted: 1031   Special Judge Description ACM has bought a new crane (crane -- je?áb) . The crane consists of n segments of various lengths, connected by flexible joints. The

14周 wtw

题就做了两道 poj1436 线段树 参考了别人的代码,注意其中hash数组的操作,很巧妙(有点像滚动数组,节省了一维的空间,否则会爆内存 然后是 poj2991  这个没啥好说的,区间add 省赛题解今天才看到,明天好好过一遍 做图形学的课程设计花了好多时间~往后几个星期课上该复习的复习事情更多了,下星期一定记得打cf  orz

线段树题目总结

一.单点更新 1.hdu1166 敌兵布阵:有N个兵营,每个兵营都给出了人数ai(下标从1开始),有四种命令,(1)"Addij",表示第i个营地增加j人.(2)"Sub i j",表示第i个营地减少j人.(3)"Query ij",查询第i个营地到第j个营地的总人数.(4)"End",表示命令结束.解题报告Here. 2.hdu1754 I Hate It:给你N个数,M个操作,操作分两类.(1)"QAB"

数据结构---线段树

线段树 转载请注明出处,谢谢!http://blog.csdn.net/metalseed/article/details/8039326  持续更新中···   一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树

(转载)线段树模板(来自胡浩大牛)

http://www.notonlysuccess.com/(今天看二叉树,想回来看看,发现大牛博客进不去...) 如果要学,就要好好学.我copy的,如有错,请看http://www.cnblogs.com/Mu-Tou/archive/2011/08/11/2134427.html [完全版]线段树 很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章了,觉得当时的代码风格实在是太丑了,很多线段树的初学者

线段树完全版【代码集合

可能有些题要重写,先放这么多 单点更新 1.hdu1166敌兵布阵 1 #include <stdio.h> 2 #define maxn 200000 3 #include <algorithm> 4 using namespace std; 5 int qr, ql, v, x, l, n, ans; 6 int tree[maxn]; 7 void build(int o, int l,int r) { 8 if (l == r) { 9 scanf("%d&quo

线段树总结 (转载 里面有扫描线类 还有NotOnlySuccess线段树大神的地址)

转载自:http://blog.csdn.net/shiqi_614/article/details/8228102 之前做了些线段树相关的题目,开学一段时间后,想着把它整理下,完成了大牛NotOnlySuccess的博文“完全版线段树”里的大部分题目,其博文地址Here,然后也加入了自己做过的一些题目.整理时,更新了之前的代码风格,不过旧的代码仍然保留着. 同样分成四类,不好归到前四类的都分到了其他.树状数组能做,线段树都能做(如果是内存限制例外),所以也有些树状数组的题目,会标示出来,并且放

线段树——转

  一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍 2:基本操作(demo用的是查询区间最小值) 线段树的主要操作有: (1):线段树的构造 void build(int node,