NC233187. Dynamic Convex Hull
描述
输入描述
This problem contains multiple test cases.
The first line contains an integer — the number of test cases.
For each test case:
The first line contains an integer — the number of the initial points.
Then lines follow. The -th of them contains two integers — the coordinate of the -th initial point.
The next line contains an integer — the number of queries.
Then queries follow. For each query: the first line contains an integer — the number of points in this query; then lines follow, the -th of which contains two integers — the coordinate of the -th point in this query.
It is guaranteed that in all test cases, the sum of N is no more than , and the sum of is no more than .
输出描述
For each query in each test case, output in one line. indicates the area in this query.
It can be proved that is always an integer.
示例1
输入:
1 8 -1 2 -2 1 -2 -1 -1 -2 1 -2 2 -1 2 1 1 2 1 3 0 3 0 4 1 5
输出:
39
C++ 解法, 执行用时: 1212ms, 内存消耗: 16836K, 提交时间: 2022-05-11 13:28:58
#include<bits/stdc++.h> using namespace std; typedef long long ll; const double eps = 0; double sgn(double x) { return x<-eps ? -1 : x>eps ? 1 : 0; } struct point { ll x, y; int id = -1; bool operator==(const point& a)const { return abs(x - a.x) <= eps && abs(y - a.y) <= eps; } bool operator<(const point& a)const { return abs(x - a.x) <= 0 ? y < a.y - eps : x < a.x - eps; } ll operator^(const point& a)const { return x * a.y - y * a.x; } point operator*(const ll& k) const { return { k * x, k * y }; } ll operator*(const point& a)const { return x * a.x + y * a.y; } double dis(const point& a)const { return sqrt((x - a.x) * (x - a.x) + (y - a.y) * (y - a.y)); } double len()const { return sqrt(x * x + y * y); } point operator-(const point& a)const { return { x - a.x, y - a.y }; } point operator-()const { return { -x, -y }; } point operator+(const point& a)const { return { x + a.x, y + a.y }; } }; struct line { point p, v; line() :p(), v() {}; line(point a, point b) :p(a), v(b) {}; double dis(const point& a)const { return abs(v ^ (a - p)) / v.len(); } point inter(const line& a)const { return p + v * ((a.v ^ (p - a.p)) / (v ^ a.v)); }//两直线相交 }; bool ons(point a1, point a2, point p)//判点p在线段a1,a2上 { if (sgn((p - a1) ^ (p - a2)) != 0)return false; if (p == a1 || p == a2)return true; return sgn((a1 - p) * (a2 - p)) <= 0; } struct polygon { vector<point> p; size_t nxt(const size_t i) const { return i == p.size() - 1 ? 0 : i + 1; } size_t pre(const size_t i) const { return i == 0 ? p.size() - 1 : i - 1; } double circ() const { double sum = 0; for (size_t i = 0; i < p.size(); i++) sum += p[i].dis(p[nxt(i)]); return sum; } double area2() const { double sum = 0; for (size_t i = 0; i < p.size(); i++) sum += p[i] ^ p[nxt(i)]; return abs(sum); } }; struct Convex : polygon { vector<ll>sum; void get_sum() { const auto& p = this->p; vector<ll> a(p.size()); for (size_t i = 0; i < p.size(); i++) a[i] = p[this->pre(i)] ^ p[i]; sum.resize(p.size()); partial_sum(a.begin(), a.end(), sum.begin()); } ll query_sum(const size_t l, const size_t r) const { const auto& p = this->p; if (l <= r) return sum[r] - sum[l] + (p[r] ^ p[l]); return sum[p.size() - 1] - sum[l] + sum[r] + (p[r] ^ p[l]); } ll query_sum() const { return sum.back(); } int is_in(const point& a)const//判断点是否在凸包内log复杂度 1表示在内部 -1表示在边界 0 表示在外部 { if (p.size() == 1 && a == p[0])return -1; if (p.size() == 2 && ons(p[0], p[1], a))return -1; if (a == p[0])return -1; int l = 1, r = p.size() - 2; while (l <= r) { int mid = (l + r) >> 1; const auto t1 = (p[mid] - p[0]) ^ (a - p[0]), t2 = (p[mid + 1] - p[0]) ^ (a - p[0]); if (t1 >= 0 && t2 <= 0) { if (mid == 1 && ons(p[0], p[mid], a))return -1; if (mid + 1 == p.size() - 1 && ons(p[0], p[mid + 1], a))return -1; if (ons(p[mid], p[mid + 1], a))return -1; return ((p[mid + 1] - p[mid]) ^ (a - p[mid])) > 0; } if (t1 < 0)r = mid - 1; else l = mid + 1; } return 0; } template<typename F>size_t extreme(const F& dir)const { const auto& p = this->p; const auto check = [&](const size_t i) {return (dir(p[i]) ^ (p[this->nxt(i)] - p[i])) >= 0; }; const auto dir0 = dir(p[0]); const auto check0 = check(0); if (!check0 && check(p.size() - 1))return 0; const auto cmp = [&](const point& v) { const size_t vi = &v - p.data(); const auto checkv = check(vi); const auto t = (dir0 ^ (v - p[0])); return checkv ^ (checkv == check0 && ((!check0 && t <= 0) || (check0 && t < 0))); }; return partition_point(p.begin(), p.end(), cmp) - p.begin(); } pair<int, int>tangent(const point& a)const //求a与凸包的两个切点 ,返回(相对于点左边的切点,相对于点右边的切点) { const size_t i = extreme([&](const point& u) {return u - a; }); const size_t j = extreme([&](const point& u) {return a - u; }); return { i,j }; } pair<size_t, size_t> tangent(const line& a) const //求直线平移后与凸包的两个切点,返回(相对于点左边的切点,相对于点右边的切点) { const size_t i = extreme([&](...) {return a.v; }); const size_t j = extreme([&](...) {return -a.v; }); return { i,j }; } }; vector<point> convexhull(vector<point>p) { vector<point>st; sort(p.begin(), p.end()); const auto check = [](const vector<point>& st, const point& u) { const auto back1 = st.back(), back2 = *prev(st.end(), 2); return ((back1 - back2) ^ (u - back2)) <= 0; }; for (const point& u : p) { while (st.size() >= 2 && check(st, u))st.pop_back(); st.push_back(u); } int k = st.size(); p.pop_back(), reverse(p.begin(), p.end()); for (const point& u : p) { while (st.size() > k && check(st, u))st.pop_back(); st.push_back(u); } st.pop_back(); return st; } long long solve(const Convex& poly, const vector<point>& vec) { if (poly.p.size() <= 10) { vector<point> tmp = vec; tmp.insert(tmp.end(), poly.p.begin(), poly.p.end()); Convex t;t.p = convexhull(tmp); t.get_sum(); return t.query_sum(); } vector<point> tmp; for (point u : vec) { if (poly.is_in(u)) continue; const auto [x, y] = poly.tangent(u); point px = poly.p[x], py = poly.p[y]; px.id = x; py.id = y; tmp.push_back(u); tmp.push_back(px); tmp.push_back(py); } if (tmp.empty()) return poly.query_sum(); Convex t;t.p = convexhull(tmp); t.get_sum(); long long ans = t.query_sum(); for (size_t i = 0; i < t.p.size(); i++) { const auto j = t.nxt(i); if (t.p[i].id != -1 && t.p[j].id != -1) { ans += poly.query_sum(t.p[i].id, t.p[j].id); } } return ans; } int main() { int t; scanf("%d", &t); while (t--) { int n; scanf("%d", &n); vector<point>tmp(n); for (int i = 0; i < n; i++) { int x, y; scanf("%d%d", &x, &y); tmp.push_back({ x,y }); } Convex pp; pp.p = convexhull(tmp); pp.get_sum(); int m; cin >> m; for (int i = 1; i <= m; i++) { int k; scanf("%d", &k); vector<point>tmp(k); for (int j = 0; j < k; j++) { int x, y; scanf("%d%d", &x, &y); tmp.push_back({ x,y }); } printf("%lld\n", solve(pp, tmp)); } } getchar(); getchar(); return 0; }
C++(g++ 7.5.0) 解法, 执行用时: 1165ms, 内存消耗: 6236K, 提交时间: 2022-11-25 16:57:42
#include<bits/stdc++.h> using namespace std; using ll = long long; constexpr ll eps = 0; struct point{ ll x, y; bool operator < (const point &a) const{ if(abs(x-a.x)<=eps) return y < a.y-eps; return x < a.x-eps; } bool operator == (const point &a) const{ return abs(x-a.x)<=eps and abs(y-a.y)<=eps; } point operator - () const{ return {-x, -y}; } point operator + (const point &a) const{ return {x+a.x, y+a.y}; } point operator - (const point &a) const{ return {x-a.x, y-a.y}; } ll operator * (const point &a) const{ return x*a.x + y*a.y; } ll operator ^ (const point &a) const{ return x*a.y - y*a.x; } int to_left(const point &a) const{ const auto t = (*this) ^ a; return (t>eps) - (t<eps); } }; struct line{ point p, v; }; struct segment{ point a,b; int is_on(const point &p) const{ if(p==a or p==b) return -1; return (p-a).to_left(p-b)==0 and (p-a)*(p-b)<-eps; } }; struct convex{ vector<point>p; size_t nxt(const size_t i) const{ return i==p.size()-1?0:i+1; } size_t pre(const size_t i) const{ return i==0?p.size()-1:i-1; } ll area2(){ ll sum = 0; for(size_t i = 0 ; i < p.size() ; i ++) sum += (p[i]^p[nxt(i)]); return sum; } template<typename F> size_t extreme(const F &dir) const{ const auto &p = this->p; const auto check = [&](const size_t i){ return dir(p[i]).to_left(p[nxt(i)]-p[i])>=0; }; const auto dir0 = dir(p[0]); const auto check0 = check(0); if(!check0 and check(p.size()-1)) return 0; const auto cmp = [&](const point &v){ const size_t &vi = &v-p.data(); if(vi==0) return 1; const auto checkv = check(vi); const auto t = dir0.to_left(v-p[0]); if(vi==1 and checkv==check0 and t==0) return 1; return checkv ^ (checkv==check0 and t<=0); }; return partition_point(begin(p), end(p), cmp) - begin(p); } int is_in(const point &a) const{ const auto &p = this->p; if(p.size()==1) return a==p[0]?-1:0; if(p.size()==2) return segment{p[0], p[1]}.is_on(a)?-1:0; if(a==p[0]) return -1; if((p[1]-p[0]).to_left(a-p[0])==-1 or (p.back()-p[0]).to_left(a-p[0])==1) return 0; const auto cmp = [&](const point &u, const point &v){ return (u-p[0]).to_left(v-p[0])==1; }; const size_t i = lower_bound(begin(p)+1, end(p), a, cmp)-begin(p); if(i==1) return segment{p[0], p[i]}.is_on(a)?-1:0; if(i==p.size()-1 and segment{p[0], p[i]}.is_on(a)) return -1; return (p[i]-p[i-1]).to_left(a-p[i-1]) > 0; } pair<size_t, size_t> tangent(const point &a) const{ const size_t i = extreme([&](const point &u){return u-a;}); const size_t j = extreme([&](const point &u){return a-u;}); return {i, j}; } vector<ll>sum; void init_sum(){ size_t n = p.size(); sum.assign(n+1, 0); for(size_t i = 1 ; i <= n ; i ++){ sum[i] = (p[i-1]^p[nxt(i-1)]); } for(size_t i = 1 ; i <= n ; i ++){ sum[i] += sum[i-1]; } } ll get_area(int l, int r){ if(l<r) return sum[r] - sum[l] + (p[r]^p[l]); else return sum[p.size()]-sum[l] + sum[r] + (p[r]^p[l]); } }; convex ConvexHull(vector<point>p){ vector<point> st; if(p.empty()) return convex{st}; sort(begin(p), end(p)); const auto check = [](const vector<point>&st, const point &u){ const auto back1 = st.back(), back2 = *prev(st.end(), 2); return (back1-back2).to_left(u-back1) <= 0; }; for(const auto &u: p){ while(st.size()>1 and check(st, u)) st.pop_back(); st.push_back(u); } size_t k = st.size(); p.pop_back(); reverse(begin(p), end(p)); for(const auto &u: p){ while(st.size()>k and check(st, u)) st.pop_back(); st.push_back(u); } st.pop_back(); return convex{st}; } void solve(){ int n; cin >> n; vector<point>vec(n); for(auto &[x,y]: vec) cin >> x >> y; auto c = ConvexHull(vec); ll old_area = c.area2(); n = c.p.size(); c.init_sum(); int m; cin >> m; while(m--){ int k; cin >> k; vector<point>tmp(k); for(auto &[x,y]: tmp) cin >> x >> y; vector<pair<size_t, size_t>>seg; vector<point>all; for(const auto &u: tmp){ if(c.is_in(u)!=0) continue; auto [l,r] = c.tangent(u); seg.push_back({l, r}); all.push_back(u); all.push_back(c.p[l]); all.push_back(c.p[r]); } ll del_area = ConvexHull(all).area2(); auto merge = [](vector<pair<size_t, size_t>>&seg, int n)->void{ vector<pair<size_t, size_t>>tmp; for(auto [l, r]: seg){ if(l<r) tmp.push_back({l, r}); else tmp.push_back({0, r}), tmp.push_back({l, n}); } sort(tmp.begin(), tmp.end()); seg.clear(); for(auto [l,r]: tmp){ if(seg.empty()) seg.push_back({l, r}); else{ auto &[l0, r0] = seg.back(); if(l<=r0) r0 = max(r0, r); else seg.push_back({l, r}); } } if(seg[0]==pair<size_t, size_t>{0,n}) { seg[0] = {0,0}; } else if(seg.size()>=2){ auto [l1,r1] = seg[0]; auto [l2,r2] = seg.back(); if(r2==n) seg[0] = {l2, r1}, seg.pop_back(); } }; merge(seg, n); ll ans = old_area + del_area; // cout << old_area << ' ' << del_area << endl; vector<point>inner; for(auto [l,r]: seg){ // cout << l << ' ' << r << endl; ans -= c.get_area(l, r); inner.push_back(c.p[l]); inner.push_back(c.p[r]); } ans -= ConvexHull(inner).area2(); cout << ans << '\n'; } } int main() { ios::sync_with_stdio(false); cin.tie(0); int t; cin >> t; while(t--){ solve(); } return 0; }