atc abc472F 思路分享(凸包的面积、质心)
题目链接
题意
逆时针给定一个凸多边形的点集 \(P\),有 \(q\) 个询问,每个询问给定 \(u,v\),求 \(P_u \to P_v\) 的有向直线右侧构成的凸多边形的质心.
\(4\le n \le 3\times 10^4\),\(1\le q \le 2\times 10^5\).
思路
令 \(P_{n+1} = P_1\),凸多边形的面积为:
\[S = \frac{\sum_{i=1}^{n}{cross(P_i,P_{i+1})}}{2}
\]
凸多边形质心 \((C_x,C_y)\) 为:
\[\begin{cases}
C_x = \dfrac{\sum_{i=1}^{n}{(X_i+X_{i+1})\cdot cross(P_i,P_{i+1})}}{3\sum_{i=1}^{n}{cross(P_i,P_{i+1})}} \\[1em]
C_y = \dfrac{\sum_{i=1}^{n}{(Y_i+Y_{i+1})\cdot cross(P_i,P_{i+1})}}{3\sum_{i=1}^{n}{cross(P_i,P_{i+1})}}
\end{cases}
\]
前缀和维护即可,时间复杂度 \(\mathcal{O}(n+q)\).
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using i128 = __int128;
struct point{
int x,y;
point(int x=0,int y=0):x(x),y(y){}
point operator+(const point& o)const{return {x+o.x,y+o.y};}
point operator-(const point& o)const{return {x-o.x,y-o.y};}
i128 operator^(const point& o)const{return (i128)x*o.y-(i128)o.x*y;}
};
void solve(){
int n,q;
cin >> n >> q;
vector<point> a(n<<1|1);
for (int i=1;i<=n;i++){
int x,y;
cin >> x >> y;
a[i] = a[i+n] = {x,y};
}
vector<i128> upX(n<<1),down(n<<1),upY(n<<1);
for (int i=1;i<n<<1;i++){
upX[i] = upX[i-1]+(a[i].x+a[i+1].x)*(a[i]^a[i+1]);
upY[i] = upY[i-1]+(a[i].y+a[i+1].y)*(a[i]^a[i+1]);
down[i] = down[i-1]+3*(a[i]^a[i+1]);
}
while (q--){
int u,v;
cin >> u >> v;
if (v<u) v+=n;
double X = (upX[v-1]-upX[u-1]+(a[v].x+a[u].x)*(a[v]^a[u]))*1.0/(down[v-1]-down[u-1]+3*(a[v]^a[u]));
double Y = (upY[v-1]-upY[u-1]+(a[v].y+a[u].y)*(a[v]^a[u]))*1.0/(down[v-1]-down[u-1]+3*(a[v]^a[u]));
cout << fixed << setprecision(12) << X << ' ' << Y << '\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号