【高手训练】【树状数组】电子速度

题目

选取显像管的任意一个平面,一开始平面内有 n n n个电子,初始速度分别为 v i v_i vi,定义飘升系数为:
∑ 1 ≤ i ≤ j ≤ n ∣ v i × v j ∣ 2 ( × 表 示 叉 乘 ) \sum_{1\leq i \leq j \leq n} |v_i \times v_j|^2(\times表示叉乘) 1ijnvi×vj2(×)
电子的速度常常会发生变化。也就是说,有两种类型的操作:

1    p    x    y 1\ \ p\ \ x\ \ y 1  p  x  y p p p 改为 ( x ,   y ) (x,\ y) (x, y)

2    l    r 2\ \ l\ \ r 2  l  r询问 [ l , r ] [l, r] [l,r] 这段区间内的电子的飘升系数。

答案对 20170927 20170927 20170927 取模即可。

Solution

观察答案并推导:
a n s   = ∑ 1 ≤ i < j ≤ n ( x i y j − x j y i ) 2 = ∑ 1 ≤ i < j ≤ n x i 2 y j 2 + ∑ 1 ≤ i < j ≤ n x j 2 y i 2 − 2 ∑ 1 ≤ i < j ≤ n x i x j y i y j = ∑ 1 ≤ i , j ≤ n [ i ≠ j ] x i 2 y j 2 − ∑ 1 ≤ i , j ≤ n [ i ≠ j ] ( x i y i ⋅ x j y j ) = ( ∑ i = 1 n x i 2 ⋅ ∑ i = 1 n y i 2 − ∑ i = 1 n ( x i 2 y i 2 ) ) − ( ∑ i = 1 n x i y i ⋅ ∑ i = 1 n x i y i − ∑ i = 1 n ( x i y i ) 2 ) = ∑ i = 1 n x i 2 ⋅ ∑ i = 1 n y i 2 − ( ∑ i = 1 n x i y i ) 2 \begin{aligned} ans\ &= \sum_{1 \leq i < j \leq n} \mathrm{(x_iy_j - x_jy_i)^2} \\ &=\sum_{1 \leq i < j \leq n} \mathrm{x_i^2y_j^2} + \sum_{1 \leq i < j \leq n} \mathrm{x_j^2y_i^2} - 2\sum_{1 \leq i < j \leq n}\mathrm{x_ix_jy_iy_j}\\ &=\sum_{1 \leq i, j \leq n}\mathrm{[i ≠j]x_i^2y_j^2} - \sum_{1 \leq i,j \leq n}\mathrm{[i ≠ j] (x_iy_i \cdot x_jy_j)} \\ &= (\sum_{i = 1}^{n}x_i^2 \cdot \sum_{i = 1}^{n}y_i^2 - \sum_{i = 1}^{n}(x_i^2y_i^2) )- (\sum_{i = 1}^{n} x_iy_i \cdot \sum_{i = 1}^{n}x_iy_i - \sum_{i = 1}^{n}(x_iy_i)^2) \\ &=\sum_{i = 1}^{n}x_i^2 \cdot \sum_{i = 1}^{n}y_i^2 - (\sum_{i = 1}^{n} x_iy_i)^2 \end{aligned} ans =1i<jn(xiyjxjyi)2=1i<jnxi2yj2+1i<jnxj2yi221i<jnxixjyiyj=1i,jn[i=j]xi2yj21i,jn[i=j](xiyixjyj)=(i=1nxi2i=1nyi2i=1n(xi2yi2))(i=1nxiyii=1nxiyii=1n(xiyi)2)=i=1nxi2i=1nyi2(i=1nxiyi)2
三个树状数组维护三个值 ∑ i = 1 n x i 2 \sum_{i = 1}^n x_i^2 i=1nxi2 ∑ i = 1 n y i 2 \sum_{i = 1}^n y_i^2 i=1nyi2 ∑ i = 1 n x i y j \sum_{i = 1}^nx_iy_j i=1nxiyj,三个值。这样就可以支持修改操作并快速维护答案了。

C o d e : \mathrm{Code:} Code:

#include <bits/stdc++.h>
#define N 1000110
#define mod 20170927
using namespace std;
int n, m;

inline int add(int a, int b) {
    if (b < 0)
        return (a + b < 0 ? a + b + mod : a + b);
    else
        return (a + b >= mod ? a + b - mod : a + b);
}// add函数把加减写一起
inline int del(int a, int b) { return a - b < 0 ? a - b + mod : a - b; }
inline int mul(int a, int b) { return 1LL * a * b % mod; }

inline int read() {
    int s = 0, w = 1;
    char c = getchar();
    while ((c > '9' || c < '0') && c != '-') c = getchar();
    if (c == '-') w = -1, c = getchar();
    while (c <= '9' && c >= '0')
        s = (s << 3) + (s << 1) + c - '0', c = getchar();
    return s * w;
}
void write(int x) {
    if (x < 0) x = ~x + 1, putchar('-');
    if (x > 9) write(x / 10);
    putchar(x % 10 + 48);
    return void();
}

struct vec {
    int x, y;
    vec() {}
    vec(int _x, int _y) {
        x = _x;
        y = _y;
    }
    inline vec operator-() { return vec(-x, -y); }
} v[N];
struct BIT {
    int a[N], b[N], c[N];
    void Inc(int x, vec v, int w) { //w为加&减的处理。
        for (; x <= n; x += x & (-x)) {
            a[x] = add(a[x], w * mul(v.x, v.x));
            b[x] = add(b[x], w * mul(v.y, v.y));
            c[x] = add(c[x], w * mul(v.x, v.y));
        }
    }
    int aska(int x) {
        int sum = 0;
        for (; x; x -= x & (-x)) sum = add(sum, a[x]);
        return sum;
    }
    int askb(int x) {
        int sum = 0;
        for (; x; x -= x & (-x)) sum = add(sum, b[x]);
        return sum;
    }
    int askc(int x) {
        int sum = 0;
        for (; x; x -= x & (-x)) sum = add(sum, c[x]);
        return sum;
    }
    int Ask(int l, int r) {
        int s1 = del(aska(r), aska(l - 1));
        int s2 = del(askb(r), askb(l - 1));
        int s3 = del(askc(r), askc(l - 1));
        return del(mul(s1, s2), mul(s3, s3));
    }
} B;
signed main() {
    n = read();
    m = read();
    for (int i = 1; i <= n; ++i) {
        int x = read(), y = read();
        v[i] = vec(x, y);
        B.Inc(i, v[i], 1);
    }
    for (int i = 1; i <= m; ++i) {
        int opt = read();
        if (opt == 1) {
            int p = read(), x = read(), y = read();
            vec tmp = vec(x, y);
            B.Inc(p, v[p], -1);
            B.Inc(p, tmp, 1);
            v[p] = tmp;
        }
        if (opt == 2) {
            int x = read(), y = read();
            write(B.Ask(x, y));
            putchar(10);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值