标签:fixed int const 答案 its 方法 empty seve ever
Input
Output
Sample Input
2 1 10 5 1 90 3 2 5 5 5 1 270 2 90
Sample Output
5.00 10.00 -10.00 5.00 -5.00 10.00
这是一道比较搞的线段树+计算几何题,结合白书简单归纳下本题:
1.这道题因为每次修改一个值以后从第n块的坐标都会发生变化,所以如果2e5的数据量去模拟当场超时,而用logn的模拟方法就是线段树。
2.所以说得用线段树,算坐标很麻烦,不如直接计算两段向量的和直接算出坐标,第一段向量A的坐标从第一块指向到n/2块,第二段向量B的坐标从n/2到n + 1(都是起始块的头指向末尾块的头,例如n = 2,第一块1头->2头,第二块2头->3头(也就是2尾))。
3.我们假定向量A始终在y轴上,我们如果知道了向量B与y轴的角度就能知道答案了,但是,这个角度因为我们假定A始终在y轴上而无法实现,但是我们可以记录B相对A的角度,通过B的长度乘以cos得到横坐标,但是就白书上给的具体公式而言,我是这么想的:首先题目以-90度为0点,所以当输入a时(a为输入的角度),角度从Π变到了a度,以y轴的负轴为0,逆时针为正,一开始B向量就是Π,后来变成了a,用a-Π就得到了变化的情况,但是我们知道,最开始B向量相对坐标轴(注意,这里不是相对y轴负轴)为90度,变化了a-Π,所以实际上相对于坐标轴变化了a-Π+Π/2度,所以应当是cos(a-Π/2),举例子:当有2个线段,把第一个与第二个的夹角变成90度,实际上相对坐标轴B向量与坐标轴角度为0(与实际的情况也相同),cos0 = 1, sin0 = 0,所以终点的坐标为(xa(A向量的横轴长度)+ |B|*cos0,ya + |B| *sin0)。
4.3这是一开始的情况,所以我们必须考虑接下来的多个的情况,如果更新只有一个线段为B的向量之后,这个A向量与B向量矢量和结果C如果作为别的的B向量,那么实际上直接拿C向量计算x,y轴相对新的A向量的增量是不会出错的,因为已经在前一次递归中算过了,所以无需再次累加新的A向量与C向量的夹角,但是,如果C向量是新的A向量,那么当我们把新的A摆到y正向时,新的B的末端与原点连成的向量与x正向所呈的角度减少了一定角度,而这个角度等于把新的A摆到y正向移动的角度,所以我们不能仅仅只算AB间夹角的影响,还要考虑A与y轴正向的夹角,因为缺少的角度是等于摆到y轴正向的角度的,所以当C作为新的A时,B的末端相对坐标轴不只是之前的向量相对坐标轴的角度,还要加上A的偏移角度,这样才能得到正确的结果。
//看此代码之前一定要在看看白书的3.3.1的内容和例题 #include <cstdio> #include <cmath> int n, c; int l[10005], s, ang;//ang对应白书的A数组 double a;//对应白书solve()的double a; struct Node{ double x; double y; double a;//该向量对应与坐标轴的角度,对应白书的ang }node[(1<<15) - 1]; double pre[10005];//对应白书的prv【】 void init(int k, int start, int end) { node[k].x = node[k].a = 0.0; if(end - start == 1) node[k].y = l[start]; else { int chl = k * 2 + 1, chr = k * 2 + 2; int mid = (start + end) / 2; init(chl, start, mid); init(chr, mid, end); node[k].y = node[chl].y + node[chr].y; } } void update(int k, int start, int end) { if(start >= s || end <= s)//如果要更新的点不在现在的范围内(一定要包含,且不为两端点),那么不会该值不会发生改变,所以没必要。 return; else { int chl = 2 * k + 1, chr = 2 * k + 2; int mid = (start + end) / 2; update(chl, start, mid); update(chr, mid, end); if(s <= mid)
//如果修改的s在此段作为B向量,那么上次递归时B向量已经更新了,但如果作为A向量,那么B末端相对原点角度会移动一个角度,这个角度等于A变化的角度,所以我们假定A旋转到y正向,因为我们只保存B相对A的角度,那么B此时相对坐标轴是原来B相对坐标轴的角度减去A变化的角度,所以得加起来 node[k].a += a - pre[s]; //新的x = A的x + |B| * cos(A变化的角度 + B之前的角度);变化的角度对应node[k].a,之前的对应arccos(node[chr].x / |B|) double sing = sin(node[k].a), cosg = cos(node[k].a); node[k].x = node[chl].x + (cosg * node[chr].x - sing * node[chr].y); node[k].y = node[chl].y + (sing * node[chr].x + cosg * node[chr].y); } } int main() { while(scanf("%d %d", &n, &c) != EOF) { for(int i = 0; i < n; i++) { scanf("%d", &l[i]); pre[i] = acos(-1); } init(0, 0, n); for(int i = 0; i < c; i++) { scanf("%d %d", &s, &ang); a = ang / 360.0 * 2 * acos(-1); update(0, 0, n); pre[s] = a; printf("%.2f %.2f\n", node[0].x, node[0].y); } } return 0; }
挑战程序设计竞赛3.3例题:Crane POJ - 2991
标签:fixed int const 答案 its 方法 empty seve ever
原文地址:https://www.cnblogs.com/jacobfun/p/12575204.html