Description
给定 nnn 个向量 a=(a1→,a2→,⋯ ,an→)a=(\overrightarrow{a_1},\overrightarrow{a_2},\cdots,\overrightarrow{a_n})a=(a1,a2,⋯,an),有 mmm 个操作分五种:
- add(i,x,y)\operatorname{add}(i,x,y)add(i,x,y):执行 ai→←ai→+(x,y)→\overrightarrow{a_i} \gets \overrightarrow{a_i} + \overrightarrow{(x,y)}ai←ai+(x,y).
- minus(i,x,y)\operatorname{minus}(i,x,y)minus(i,x,y):执行 ai→←ai→−(x,y)→\overrightarrow{a_i} \gets \overrightarrow{a_i} - \overrightarrow{(x,y)}ai←ai−(x,y).
- mul(i,k)\operatorname{mul}(i,k)mul(i,k):执行 ai→←kai→\overrightarrow{a_i} \gets k\overrightarrow{a_i}ai←kai.
- dot(l,r)\operatorname{dot}(l,r)dot(l,r):求 ∑i=lr−1∑j=i+1rai→⋅aj→\sum\limits_{i=l}^{r-1} \sum\limits_{j=i+1}^r \overrightarrow{a_i} \cdot \overrightarrow{a_j}i=l∑r−1j=i+1∑rai⋅aj.
- cross(l,r)\operatorname{cross}(l,r)cross(l,r):求 ∑i=lr−1∑j=i+1rai→×aj→\sum\limits_{i=l}^{r-1} \sum\limits_{j=i+1}^r \overrightarrow{a_i} \times \overrightarrow{a_j}i=l∑r−1j=i+1∑rai×aj.
Limitations
2≤n≤1052 \le n \le 10^52≤n≤105
1≤m≤1051 \le m \le 10^51≤m≤105
1≤i,l,r≤n, l<r1 \le i,l,r \le n, \;l <r1≤i,l,r≤n,l<r
任意时刻 ∣xi∣,∣yi∣≤1000|x_i|,|y_i| \le 1000∣xi∣,∣yi∣≤1000
1.5s,500MB1.5\text{s},500\text{MB}1.5s,500MB
Solution
下记:
- ∙l,r=∑i=lr−1∑j=i+1rai→×aj→\bullet_{l,r}=\sum\limits_{i=l}^{r-1} \sum\limits_{j=i+1}^r \overrightarrow{a_i} \times \overrightarrow{a_j}∙l,r=i=l∑r−1j=i+1∑rai×aj
- ×l,r=∑i=lr−1∑j=i+1rai→×aj→\times_{l,r}=\sum\limits_{i=l}^{r-1} \sum\limits_{j=i+1}^r \overrightarrow{a_i} \times \overrightarrow{a_j}×l,r=i=l∑r−1j=i+1∑rai×aj
- Xl,r=∑i=lrxi,Yl,r=∑i=lryiX_{l,r}=\sum_{i=l}^r x_i,Y_{l,r}=\sum_{i=l}^r y_iXl,r=∑i=lrxi,Yl,r=∑i=lryi
因为点乘具有交换律和分配律,所以:
∙l,r=∙l,mid+∙mid+1,r+Xl,mid×Xmid+1,r+Yl,mid×Ymid+1,r\bullet_{l,r}=\bullet_{l,mid}+\bullet_{mid+1,r}+X_{l,mid}\times X_{mid+1,r}+Y_{l,mid}\times Y_{mid+1,r}∙l,r=∙l,mid+∙mid+1,r+Xl,mid×Xmid+1,r+Yl,mid×Ymid+1,r
但叉乘只有分配律,所以:
×l,r=×l,mid+×mid+1,r+Xl,mid×Ymid+1,r−Yl,mid×Xmid+1,r\times_{l,r}=\times_{l,mid}+\times_{mid+1,r}+X_{l,mid}\times Y_{mid+1,r}-Y_{l,mid}\times X_{mid+1,r}×l,r=×l,mid+×mid+1,r+Xl,mid×Ymid+1,r−Yl,mid×Xmid+1,r
知道了这些,就可以用线段树维护了。
Code
3.20KB,112ms,12.98MB (in total, C++20 with O2)3.20\text{KB},112\text{ms},12.98\text{MB}\;\texttt{(in total, C++20 with O2)}3.20KB,112ms,12.98MB(in total, C++20 with O2)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
struct Node {
int l, r;
i64 sumX, sumY, dot, cross;
};
using Tree = vector<Node>;
inline int ls(int u) { return 2 * u + 1; }
inline int rs(int u) { return 2 * u + 2; }
inline void merge(Node& res, const Node& L, const Node& R) {
res.sumX = L.sumX + R.sumX;
res.sumY = L.sumY + R.sumY;
res.dot = L.dot + R.dot + L.sumX * R.sumX + L.sumY * R.sumY;
res.cross = L.cross + R.cross + L.sumX * R.sumY - L.sumY * R.sumX;
}
inline void pushup(Tree& tr, int u) { merge(tr[u], tr[ls(u)], tr[rs(u)]); }
inline void build(Tree& tr, int u, int l, int r,
const vector<int>& X, const vector<int>& Y) {
tr[u].l = l;
tr[u].r = r;
if (l == r) {
tr[u].sumX = X[l];
tr[u].sumY = Y[l];
return;
}
const int mid = (l + r) >> 1;
build(tr, ls(u), l, mid, X, Y);
build(tr, rs(u), mid + 1, r, X, Y);
pushup(tr, u);
}
inline void add(Tree& tr, int u, int p, int s, int t) {
if (tr[u].l == tr[u].r) {
tr[u].sumX += s;
tr[u].sumY += t;
return;
}
const int mid = (tr[u].l + tr[u].r) >> 1;
if (p <= mid) add(tr, ls(u), p, s, t);
else add(tr, rs(u), p, s, t);
pushup(tr, u);
}
inline void mul(Tree& tr, int u, int p, int v) {
if (tr[u].l == tr[u].r) {
tr[u].sumX *= v;
tr[u].sumY *= v;
return;
}
const int mid = (tr[u].l + tr[u].r) >> 1;
if (p <= mid) mul(tr, ls(u), p, v);
else mul(tr, rs(u), p, v);
pushup(tr, u);
}
inline Node query(Tree& tr, int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u];
const int mid = (tr[u].l + tr[u].r) >> 1;
if (r <= mid) return query(tr, ls(u), l, r);
else if (l > mid) return query(tr, rs(u), l, r);
else {
Node res, L = query(tr, ls(u), l, r), R = query(tr, rs(u), l, r);
merge(res, L, R);
return res;
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, q;
scanf("%d %d", &n, &q);
vector<int> x(n), y(n);
for (int i = 0; i < n; i++) scanf("%d %d", &x[i], &y[i]);
Tree tr(n << 2);
build(tr, 0, 0, n - 1, x, y);
for (int i = 0; i < q; i++) {
int op; scanf("%d", &op);
if (op == 1) {
int i, s, t;
scanf("%d %d %d", &i, &s, &t), i--;
add(tr, 0, i, s, t);
}
else if (op == 2) {
int i, s, t;
scanf("%d %d %d", &i, &s, &t), i--;
add(tr, 0, i, -s, -t);
}
else if (op == 3) {
int i, v;
scanf("%d %d", &i, &v), i--;
mul(tr, 0, i, v);
}
else if (op == 4) {
int l, r;
scanf("%d %d", &l, &r), l--, r--;
printf("%lld\n", query(tr, 0, l, r).dot);
}
else {
int l, r;
scanf("%d %d", &l, &r), l--, r--;
printf("%lld\n", query(tr, 0, l, r).cross);
}
}
return 0;
}