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;
}
posted @ 2026-08-28 15:47  kzssCCC  阅读(6)  评论(0)    收藏  举报