P6588 『JROI-1』 向量 Solution

Description

给定 n n n 个向量 a = ( a 1 → , a 2 → , ⋯   , a n → ) a=(\overrightarrow{a_1},\overrightarrow{a_2},\cdots,\overrightarrow{a_n}) a=(a1 ,a2 ,,an ),有 m m m 个操作分五种:

  • add ⁡ ( i , x , y ) \operatorname{add}(i,x,y) add(i,x,y):执行 a i → ← a i → + ( 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):执行 a i → ← a i → − ( 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):执行 a i → ← k a i → \overrightarrow{a_i} \gets k\overrightarrow{a_i} ai kai .
  • dot ⁡ ( l , r ) \operatorname{dot}(l,r) dot(l,r):求 ∑ i = l r − 1 ∑ j = i + 1 r a i → ⋅ a j → \sum\limits_{i=l}^{r-1} \sum\limits_{j=i+1}^r \overrightarrow{a_i} \cdot \overrightarrow{a_j} i=lr1j=i+1rai aj .
  • cross ⁡ ( l , r ) \operatorname{cross}(l,r) cross(l,r):求 ∑ i = l r − 1 ∑ j = i + 1 r a i → × a j → \sum\limits_{i=l}^{r-1} \sum\limits_{j=i+1}^r \overrightarrow{a_i} \times \overrightarrow{a_j} i=lr1j=i+1rai ×aj .

Limitations

2 ≤ n ≤ 1 0 5 2 \le n \le 10^5 2n105
1 ≤ m ≤ 1 0 5 1 \le m \le 10^5 1m105
1 ≤ i , l , r ≤ n ,    l < r 1 \le i,l,r \le n, \;l <r 1i,l,rn,l<r
任意时刻 ∣ x i ∣ , ∣ y i ∣ ≤ 1000 |x_i|,|y_i| \le 1000 xi,yi1000
1.5 s , 500 MB 1.5\text{s},500\text{MB} 1.5s,500MB

Solution

下记:

  • ∙ l , r = ∑ i = l r − 1 ∑ j = i + 1 r a i → × a j → \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=lr1j=i+1rai ×aj
  • × l , r = ∑ i = l r − 1 ∑ j = i + 1 r a i → × a j → \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=lr1j=i+1rai ×aj
  • X l , r = ∑ i = l r x i , Y l , r = ∑ i = l r y i X_{l,r}=\sum_{i=l}^r x_i,Y_{l,r}=\sum_{i=l}^r y_i Xl,r=i=lrxi,Yl,r=i=lryi

因为点乘具有交换律分配律,所以:
∙ l , r = ∙ l , m i d + ∙ m i d + 1 , r + X l , m i d × X m i d + 1 , r + Y l , m i d × Y m i d + 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 , m i d + × m i d + 1 , r + X l , m i d × Y m i d + 1 , r − Y l , m i d × X m i d + 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,rYl,mid×Xmid+1,r

知道了这些,就可以用线段树维护了。

Code

3.20 KB , 112 ms , 12.98 MB    (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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值