昨晚上poj进不去,今天补上
线段树+计算几何问题
因为转动第i根线段的时候,所有在其上的线段都要转动相同的角度,因为数据规模为10000,暴力计算会超时O(n*n),所以可以用线段树来解决
线段树维护两个值,一个是需要转动的角度,另一个是首线段起点到尾线段终点的向量
这道题是挑战程序设计竞赛里的,直接抄的代码,关于计算几何的一些地方还没看懂,待日后再补
#include<stdio.h>
#include<math.h>
#define MAX 10005
const double PI = acos(-1.0);
const int ST_SIZE = (1<< 15)-1;
int N,C;
int L[MAX];
int S[MAX],A[MAX];
double vx[ST_SIZE],vy[ST_SIZE]; //各节点的向量
double ang[ST_SIZE]; //各节点的角度
double prv[MAX]; //为了查询角度的变化而保存的当前角度的数组
//初始化线段树
//k是节点的编号,l、r表示当前节点对应的是[l,r)区间
void init(int k,int l,int r) {
ang[k]=vx[k]=0.0;
if(r-l==1) {
//叶节点
vy[k]=L[l];
}
else {
//非叶节点
int chl=k*2+1,chr=k*2+2;
init(chl,l,(l+r)/2);
init(chr,(l+r)/2,r);
vy[k]=vy[chl]+vy[chr];
}
}
//把s和s+1的角度变为a
//v是节点的编号,l,r表示当前节点对应的是[l,r)区间
void change(int s,double a,int v,int l,int r) {
if (s<=l) return;
else if (s<r) {
int chl=v*2+1,chr=v*2+2;
int m=(l+r)/2;
change(s,a,chl,l,m);
change(s,a,chr,m,r);
if (s<=m) ang[v]+=a;
double s=sin(ang[v]), c= cos(ang[v]);
vx[v]= vx[chl]+(c*vx[chr]-s*vy[chr]); //???????????????
vy[v]= vy[chl]+(s*vx[chr]+c*vy[chr]); //vx-vy是将第一条线段转至垂直方向后,头指向尾的向量
}
}
void solve() {
init(0,0,N);
int i;
for(i=1;i<N;i++) prv[i]=PI;
for(i=0;i<C;i++) {
int s=S[i];
double a=A[i]/360.0*2*PI;
change(s,a-prv[s],0,0,N); //a-prv[s]需要转动的角度
prv[s]=a;
printf("%.2f %.2f\n",vx[0],vy[0]);
}
}
int main() {
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&N,&C)!=EOF) {
int i;
for(i=0;i<N;i++) {
scanf("%d",&L[i]);
}
for(i=0;i<C;i++) {
scanf("%d%d",&S[i],&A[i]);
}
solve();
}
}