zoukankan      html  css  js  c++  java
  • CF618E Robot Arm- 计算几何- 线段树

    https://www.luogu.com.cn/problem/CF618E
    你有一个机械臂,它由 nn 节组成,每一节首尾相接。一开始第i节的起终点为(i-1,0),(i,0)(i−1,0),(i,0)。
    有 mm 个操作,操作有两种:
    给定 i,li,l,将第 ii 节机械臂沿着原来的方向延长 ll 个单位,其他节与这一节的相对位置不变(见题面图)。
    给定 i,alphai,α,将第 ii 节机械臂以这一节的起点为旋转中心顺时针旋转 alpha°α° ,其他节与这一节的相对位置不变(见题面图)。
    输出每个操作后最后一节的终点的坐标。


    题解

    • 线段树维护多个向量的和(题目所求为n个向量的和)
    • 操作1单点修改伸长的向量坐标,线段树单点加法
    • 操作2区间修改,标记维护旋转的角度,推一下

    向量(x,y)顺时针旋转a的弧度值得到(ycosa + xsina , ycosa - xsina)
    证明:
    设向量(x,y)的长度为R,与x轴夹角为b,则y=Rcosb,x=Rsinb
    由于旋转长度不变,旋转后长度仍为R,夹角为(a+b),因此
    y' = R *cos(a+b) = R *cosa cosb - R *sina sinb = y *cosa - x *sina
    x' = R *sin(a+b) = R *sina cosb + R *cosa sinb = y *sina + x *cosa


    代码

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <iomanip>
    using namespace std;
    const double PI=3.141592653589793;
    const int maxn=300003;
    int n,m;
    struct fdfdfd{int l,r; double endx,endy,ang;}a[maxn<<2];
    void pushup(int x) {a[x].endx=a[x<<1].endx+a[x<<1|1].endx; a[x].endy=a[x<<1].endy+a[x<<1|1].endy;}
    void pushtag(int x,double d) {
    	a[x].ang+=d;
    	double tx=a[x].endx,ty=a[x].endy;
    	a[x].endx=ty*sin(d)+tx*cos(d),a[x].endy=ty*cos(d)-tx*sin(d);
    }
    void pushdown(int x) {if(a[x].ang>1e-12) pushtag(x<<1,a[x].ang),pushtag(x<<1|1,a[x].ang),a[x].ang=0;}
    void build(int x,int left,int right)
    {
    	a[x].l=left; a[x].r=right;
    	if(left==right) {a[x].endx=1; return;}
    	int mid=left+right>>1;
    	build(x<<1,left,mid); build(x<<1|1,mid+1,right);
    	pushup(x);
    }
    void query(int x,int d,double &nowx,double &nowy)
    {
    	if(a[x].l>d||a[x].r<d) return;
    	if(a[x].l==d&&a[x].r==d) {nowx=a[x].endx,nowy=a[x].endy; return;}
    	pushdown(x);
    	query(x<<1,d,nowx,nowy); query(x<<1|1,d,nowx,nowy);
    }
    void modify_long(int x,int d,double dx,double dy)
    {
    	if(a[x].l>d||a[x].r<d) return;
    	if(a[x].l==d&&a[x].r==d) {a[x].endx+=dx,a[x].endy+=dy; return;}
    	pushdown(x);
    	modify_long(x<<1,d,dx,dy); modify_long(x<<1|1,d,dx,dy);
    	pushup(x);
    }
    void modify_rot(int x,int left,int right,double d)
    {
    	if(a[x].l>right||a[x].r<left) return;
    	if(left<=a[x].l&&right>=a[x].r) {pushtag(x,d); return;}
    	pushdown(x);
    	modify_rot(x<<1,left,right,d); modify_rot(x<<1|1,left,right,d);
    	pushup(x);
    }
    int main()
    {
    	scanf("%d%d",&n,&m); cout<<fixed<<setprecision(10);
    	build(1,1,n);
    	for(int i=1,t0,t1,t2;i<=m;++i)
    	{
    		scanf("%d%d%d",&t0,&t1,&t2);
    		if(t0==1) {
    			double x,y; query(1,t1,x,y);
    			modify_long(1,t1,x*t2/sqrt(x*x+y*y),y*t2/sqrt(x*x+y*y));
    		}
    		else modify_rot(1,t1,n,t2*PI/180.0);
    		cout<<a[1].endx<<' '<<a[1].endy<<'
    ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    收集一些dos网络配置命令,从新获取ip刷新dns
    多个线程访问共享对象和数据的方式
    Oracle rownum 分页, 排序
    ORACLE中用rownum分页并排序的SQL语句
    CentOS 6.5安装MongoDB 2.6(多yum数据源)
    【编程练习】收集的一些c++代码片,算法排序,读文件,写日志,快速求积分等等
    java枚举使用详解
    PHP+MySQL动态网站开发从入门到精通(视频教学版)
    Premiere Pro CS6标准教程
    黑客攻防:实战加密与解密
  • 原文地址:https://www.cnblogs.com/wuwendongxi/p/14186518.html
Copyright © 2011-2022 走看看