夜空与花海 (flower)
直接输出第二个样例即可获得 。
让我们来正经地看看一下这道题。不难看出,对边的描述实际上就是在描述向量,边 实际上就是向量 。所以整个多边形就是若干向量首尾相连形成的闭合图形(小性质:)。
对于第 条边,他会选择第 条边的终点 向第 条边做垂线,垂足为 。
有了刚刚对向量的理解,我们可以发现, 就是向量
发现变成了向量
显然,向量
点积:
几何表示:
坐标表示:
所以:
就很好搞了。
现在我们已经完成了计算
现在考虑向量
其中
证明:
还是从几何意义考虑,如下图:
很显然
即:
所以新的向量:
好的,现在我们知道了第
我们还是从图上考虑。如图,
根据基本的向量加减法,可以得到:
用坐标表示出来:
现在修改操作也完成了。
那么对于
由于 double
。
pair<double, double> vec[MAXN];
double abc(double a, double b)
{
return sqrt(a * a + b * b);
}
signed main()
{
vec[n + 1] = vec[1];
while(m--)
{
int opt, l, r;
scanf("%lld%lld%lld", &opt, &l, &r);
if(opt == 1)
{
double ans = 0.00;
for(int i = l; i <= r; i++)
{
ans += abs(vec[i + 1].fi * vec[i].fi + vec[i + 1].se * vec[i].se);
}
printf("%.6lf\n", ans / 2.00);
}
else
{
np ver1 = mp((abc(vec[l].fi, vec[l].se) + r) / abc(vec[l].fi, vec[l].se) * vec[l].fi, (abc(vec[l].fi, vec[l].se) + r) / abc(vec[l].fi, vec[l].se) * vec[l].se);
np ver2 = mp(vec[l].fi + vec[l + 1].fi, vec[l].se + vec[l + 1].se);
np ver3 = mp(ver2.fi - ver1.fi, ver2.se - ver1.se);
if(l == 1) vec[n + 1] = ver1;
if(l == n) vec[1] = ver3;
vec[l] = ver1;
vec[l + 1] = ver3;
}
}
return 0;
}
当然,我们也可以直接封装向量。以下代码来自庞队:
struct V{
double x,y,len;
V(){}
V(double _x,double _y){
x = _x,y = _y;
len = sqrt(x * x + y * y);
}
void get_len(){
len = sqrt(x * x + y * y);
}
}a[N];
V operator + (V a,V b){return V(a.x + b.x,a.y + b.y);}
V operator - (V a,V b){return V(a.x - b.x,a.y - b.y);}
V operator * (V a,double k){return V(a.x*k,a.y*k);}
V operator / (V a,double k){return V(a.x/k,a.y/k);}
double operator * (V a,V b){return (a.x * b.y) - (a.y * b.x);};
double touying(V a,V b){ //求 b 在 a 上的投影
double S = fabs(a * b) / 2;
double h = S / a.len * 2;
return sqrt(b.len * b.len - h * h);
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) scanf("%lf%lf",&a[i].x,&a[i].y);
for(int i=1; i<=n; i++){
a[i].get_len();
}
for(int i=1; i<=m; i++){
int opt;
scanf("%d",&opt);
if(opt == 1){
int x,y;
scanf("%d%d",&x,&y);
double ans = 0;
for(int j=x; j<=y; j++){
int now = j;
int nxt = (j == n ? 1 : j + 1);
ans += touying(a[now],a[nxt]) * a[now].len / 2;
}
printf("%.5f\n",ans);
}
else if(opt == 2){
int now;
double k;
scanf("%d%lf",&now,&k);
int nxt = (now == n) ? 1 : now + 1;
V he = a[now] + a[nxt];
double len = a[now].len;
a[now] = a[now] / len * (len + k);
a[nxt] = he - a[now];
a[now].get_len();a[nxt].get_len();
}
}
return 0;
}
在写出
对于
对于
也就是说,对于一次更改,边
这样,每次
这里我的写法是
这样我们就可以用
double gog(double a, double b)
{
return sqrt(a * a + b * b);
}
int main()
{
kkk[n + 1] = kkk[1];
kkk[n + 2] = kkk[2];
int nn = n + 2;
build(1, 1, nn);
while(m--)
{
int opt, l, r;
scanf("%d%d%d", &opt, &l, &r);
if(opt == 1)
{
printf("%.6lf\n", query(1, l, r) / 2.00);
}
else
{
np ver1 = mp((gog(kkk[l].fi, kkk[l].se) + r) / gog(kkk[l].fi, kkk[l].se) * kkk[l].fi, (gog(kkk[l].fi, kkk[l].se) + r) / gog(kkk[l].fi, kkk[l].se) * kkk[l].se);
np ver2 = mp(kkk[l].fi + kkk[l + 1].fi, kkk[l].se + kkk[l + 1].se);
np ver3 = mp(ver2.fi - ver1.fi, ver2.se - ver1.se);
kkk[l] = ver1;
kkk[l + 1] = ver3;
if(l == 1) kkk[n + 1] = ver1;
if(l == n) kkk[1] = ver3;
update(1, l, abs(kkk[l + 1].fi * kkk[l].fi + kkk[l + 1].se * kkk[l].se));
update(1, l + 1, abs(kkk[l + 2].fi * kkk[l + 1].fi + kkk[l + 2].se * kkk[l + 1].se));
if(l == 1)
{
update(1, n, abs(kkk[n].fi * kkk[1].fi + kkk[n].se * kkk[1].se));
continue;
}
update(1, l - 1, abs(kkk[l - 1].fi * kkk[l].fi + kkk[l - 1].se * kkk[l].se));
}
}
return 0;
}
细节还是很多的,建议自己上手写写。