CF853E Lada Malina【凸包,掃描線】
給定 \(n\) 個點 \(\mathbf{f_i}\) 帶權 \(a_i\) 和 \(k\) 個向量 \(\mathbf{v_i}\),\(q\) 次詢問 \(\mathbf p\) 和 \(t\),求存在實數 \(w_j\in[-t,t]\) 滿足 \(\mathbf{f_i}+\sum w_j\mathbf{v_j}=\mathbf p\) 的 \(a_i\) 之和。
\(2\le k\le 10\),\(1\le n\le 10^5\),\(|vx_i|,|vy_i|\le 10^3\),\(|fx_i|,|fy_i|,|px|,|py|\leq 10^9\),\(1\leq a_i\leq 10^9\)
後面的 \(\sum w_j\mathbf{v_j}\) 顯然是一個凸包(Minkowski 和),但這個凸包咋求呢?
若 \(vx_i<0\land vx_i=0\lor vy_i<0\) 則令 \(\mathbf{v_i}\) 取反,令 \(\mathbf p=\mathbf p-t\sum\mathbf{v_j}\),並移項得到 \(\mathbf{f_i}=\mathbf p+\sum w_j\mathbf{v_j}\),\(w_j\) 的取值範圍變為 \([0,2t]\),此時直接把所有 \(\mathbf{v_j}\) 按斜率排序,按從小到大的順序從 \(\mathbf p\)
因為凸包的邊只有 \(2k\) 條,所以可以拆成一堆底邊與 \(y\) 軸平行,直角邊在 \(-\infty\) 的直角梯形,約束即為 \(x\in[l,r]\) 和 \(y-kx\leq b\),令 \(y:=y-kx\) 之後就是二維數點,對縱座標掃描線,對橫座標離散化之後用樹狀陣列維護即可。
注意掃描線做相同縱座標時的順序(先詢問還是先修改),時間複雜度 \(O((n+q)k\log n)\)。
#include<bits/stdc++.h> #define MP make_pair #define PB emplace_back #define all(x) x.begin(), x.end() #define fi first #define se second using namespace std; typedef long long LL; typedef pair<int, int> pii; const int N = 100010; int rd(){ int ch = getchar(), x = 0; bool f = false; for(;ch < '0' || ch > '9';ch = getchar()) f |= ch == '-'; for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0'; return f ? -x : x; } int k, n, q, sx, sy, x[N], y[N], a[N], px[N], py[N], t[N]; pii v[11]; LL ans[N], tr[N]; vector<int> val; int pos(int x){return upper_bound(all(val), x) - val.begin();} struct Node { double a; int x, y, id; Node(double _a = 0, int _x = 0, int _y = 0, int _z = 0): a(_a), x(_x), y(_y), id(_z){} bool operator < (const Node &o) const {return fabs(a-o.a)<1e-7?id<o.id:a<o.a;} } w[N<<1]; bool cmp(const pii &a, const pii &b){ if(!b.fi) return a.fi || a.se < b.se; return a.se * b.fi < b.se * a.fi; } void upd(int p, int v){for(;p < N;p += p & -p) tr[p] += v;} LL qry(int p){LL r = 0; for(;p;p -= p & -p) r += tr[p]; return r;} int main(){ k = rd(); n = rd(); q = rd(); for(int i = 1;i <= k;++ i){ v[i].fi = rd(); v[i].se = rd(); if(v[i].fi < 0){ v[i].fi = -v[i].fi; v[i].se = -v[i].se; } else if(!v[i].fi && v[i].se < 0) v[i].se = -v[i].se; sx += v[i].fi; sy += v[i].se; } sort(v+1, v+k+1, cmp); for(int i = 1;i <= n;++ i){ val.PB(x[i] = rd()); y[i] = rd(); a[i] = rd(); } sort(all(val)); val.erase(unique(all(val)), val.end()); for(int i = 1;i <= q;++ i){ px[i] = rd(); py[i] = rd(); t[i] = rd(); px[i] -= sx*t[i]; py[i] -= sy*t[i]; t[i] <<= 1; } for(int i = 1;i <= k;++ i){ if(!v[i].fi){ for(int j = 1;j <= q;++ j) py[j] += v[i].se * t[j]; continue; } double k = 1.*v[i].se/v[i].fi; for(int j = 1;j <= n;++ j) w[j] = Node(y[j] - k*x[j], x[j], a[j], 0); for(int j = 1;j <= q;++ j){ w[n+j] = Node(py[j] - k*px[j], px[j], px[j] + v[i].fi*t[j], -j); px[j] += v[i].fi*t[j]; py[j] += v[i].se*t[j]; } sort(w+1, w+n+q+1); memset(tr, 0, sizeof tr); for(int j = 1;j <= n+q;++ j) if(w[j].id) ans[-w[j].id] -= qry(pos(w[j].y))-qry(pos(w[j].x-(i<2))); else upd(pos(w[j].x), w[j].y); } for(int i = 1;i <= k;++ i){ if(!v[i].fi) break; double k = 1.*v[i].se/v[i].fi; for(int j = 1;j <= n;++ j) w[j] = Node(y[j] - k*x[j], x[j], a[j], 0); for(int j = 1;j <= q;++ j){ w[n+j] = Node(py[j] - k*px[j], px[j] - v[i].fi*t[j], px[j], j); px[j] -= v[i].fi*t[j]; py[j] -= v[i].se*t[j]; } sort(w+1, w+n+q+1); memset(tr, 0, sizeof tr); for(int j = 1;j <= n+q;++ j) if(w[j].id) ans[w[j].id] += qry(pos(w[j].y-(i>1))) - qry(pos(w[j].x-1)); else upd(pos(w[j].x), w[j].y); } for(int i = 1;i <= q;++ i) printf("%lld\n", ans[i]); }