本来很操蛋的一天,就因为把这道艹哭我两天的题A了而变得好多了
题意:
一个起重机,由n个臂组成,每个臂的臂长已知,初始状态任意两个臂之间的角度为180度,给c个操作,选择第i个臂,将第s和第s+1个臂之间的角度改成a,每次讯问后输出尖端的坐标。
Input
The input consists of several instances, separated by single empty lines.
The first line of each instance consists of two integers 1 ≤ n ≤10 000 and c 0 separated by a single space -- the number of segments of the crane and the number of commands. The second line consists of n integers l1,..., ln (1 li 100) separated by single spaces. The length of the i-th segment of the crane is li. The following c lines specify the commands of the operator. Each line describing the command consists of two integers s and a (1 ≤ s < n, 0 ≤ a ≤ 359) separated by a single space -- the order to change the angle between the s-th and the s + 1-th segment to a degrees (the angle is measured counterclockwise from the s-th to the s + 1-th segment).
The first line of each instance consists of two integers 1 ≤ n ≤10 000 and c 0 separated by a single space -- the number of segments of the crane and the number of commands. The second line consists of n integers l1,..., ln (1 li 100) separated by single spaces. The length of the i-th segment of the crane is li. The following c lines specify the commands of the operator. Each line describing the command consists of two integers s and a (1 ≤ s < n, 0 ≤ a ≤ 359) separated by a single space -- the order to change the angle between the s-th and the s + 1-th segment to a degrees (the angle is measured counterclockwise from the s-th to the s + 1-th segment).
Output
The output for each instance consists of c lines. The i-th of the lines consists of two rational numbers x and y separated by a single space -- the coordinates of the end of the n-th segment after the i-th command, rounded to two digits after the decimal point.
The outputs for each two consecutive instances must be separated by a single empty line.
The outputs for each two consecutive instances must be separated by a single empty line.
这题是怎么想到线段树忘了,因为我是在挑战的例题里看到它的。。。
对臂建树,每个点维护前半段和后半段之间的角度(具体哪个角看实现方法),以及如果该段第一个臂竖直向上顶端到基点的向量。
每次更新某两个臂之间的角度时,将所有满足loc<=m的点角度都改变相同的数值,因为他们的对比基础都是改变点前面的臂。
然后维护公式是向量旋转。向量(x,y)正方向旋转phi,得到(x*cos(phi)-y*sin(phi), xsin(phi)+y*cos(phi))
公式的原理是设当前坐标为(lcosa,lsina),然后在坐标系上画一下,拆一下sin,cos就行了。
还有,头一次用面向对象写ACM题
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<fstream>
using namespace std;
#define mxn 10010
const double pi=acos(-1.0);
int n,c;
double len[mxn],angle[mxn];
class coor{
public:
double x,y;
coor(){}
coor(double a,double b){
x=a,y=b;
}
coor rotate(double ang){
double tema=cos(ang),temb=sin(ang);
return coor(x*tema-y*temb,x*temb+y*tema);
}
coor operator + (const coor& in)const{
return coor(x+in.x,y+in.y);
}
void print(){
printf("%.2lf %.2lf\n",x,y);
}
};
class node{
public:
int ll,rr;
coor end;
double ang;
};
class segment_tree{
private:
node nd[mxn<<2];
void merge(int id){
int ls=id<<1,rs=ls|1;
nd[id].end=nd[ls].end+nd[rs].end.rotate(nd[id].ang);
}
public:
void build(int l,int r,int id){
nd[id].ll=l;
nd[id].rr=r;
if(l==r){
nd[id].end=coor(0.0,len[l]);
nd[id].ang=0.0;
return;
}
int m=(l+r)>>1,ls=id<<1,rs=ls|1;
build(l,m,ls);
build(m+1,r,rs);
nd[id].ang=0.0;
merge(id);
}
void update(int loc,double x,int id){
int m=(nd[id].ll+nd[id].rr)>>1,ls=id<<1,rs=ls|1;
if(loc<=m){
nd[id].ang+=x;
}
if(nd[id].ll==nd[id].rr) return;
if(loc<=m) update(loc,x,ls);
else update(loc,x,rs);
merge(id);
}
void printAns(){
nd[1].end.print();
}
}Tree;
void init(){
Tree.build(0,n-1,1);
for(int i=0;i<n;++i) angle[i]=180.0;
}
double convert(double in){
return in*2*pi/360.0;
}
int main(){
bool first=true;
while(scanf("%d%d",&n,&c)!=EOF){
if(!first){
puts("");
}
first=false;
for(int i=0;i<n;++i) scanf("%lf",&len[i]);
init();
int s;
double a;
for(int q=0;q<c;++q){
scanf("%d%lf",&s,&a);
Tree.update(s-1,convert(a-angle[s-1]),1);
angle[s-1]=a;
Tree.printAns();
}
}
return 0;
}