天才绅士少女助手克里斯蒂娜 解题报告 天才绅士少女助手克里斯蒂娜

Description

红莉栖想要弄清楚楼下天王寺大叔的显像管电视对 “电话微波炉 (暂定)” 的影响.

选取显像管的任意一个平面, 一开始平面内有个 (n) 电子, 初始速度分别为 (v_i), 定义飘升系数为(sumlimits_{1 le i < j le n}|mathbb{v_i} imes mathbb{v_j}|^2)

由于电视会遭到大叔不同程度的暴击, 电子的速度常常会发生变化. 也就是说, 有两种类型的操
作:

  • 1 p x y 将 (mathbb{v_p}) 改为 ((x,y))

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

这么简单的问题红莉栖当然能解决, 但是她需要一个人帮忙验证一下结果的正确性.

由于唯一帮得上忙的桶子去找菲利斯了, 于是只能拜托你来完成这个任务了.

答案对 (20170927) 取模即可.

Input Format

第一行两个整数 (n, m) 表示电子个数和询问个数.
接下来 (n) 行, 每行两个整数 (x, y) 表示 (mathbb{v_i}).
接下来 (m) 行, 每行形如 1 p x y 或 2 l r, 分别表示两种操作.

Output Format

对于每个操作 (2), 输出一行一个整数表示飘升系数对 (20170927) 取模的值

测试点编号 n m
1 (le 100) (le 100)
2 (le 500) (le 500)
3 (le 1000) (le 1000)
4 (le 5000) (le 5000)
5 (le 10000) (le 10000)
6 (le 50000) (le 50000)
7 (le 100000) (le 100000)
8 (le 500000) (le 500000)
9 (le 1000000) (le 1000000)
10 (le 1000000) (le 1000000)

Solution

注意这是叉乘。。一开始当点乘了。。

对区间([l,r])的答案为

[sum_{l le i < j le r} (x_iy_j-x_jy_i)^2 ]

[=sum_{i=l}^r x_i^2 sum_{i=l}^r y_i^2- (sum_{i=l}^rx_iy_i)^2 ]

开三个树状数组就可以了

注意有点卡常,最好(O(n))初始化


Code:

#include <cstdio>
#define ll long long
const int N=1000010;
const ll mod=20170927;
ll s[3][N],x[N],y[N];
int n,m;
void change(int id,int x,ll d)
{
    while(x<=n)
        (s[id][x]+=d)%=mod,x+=x&-x;
}
ll ask(int id,int x)
{
    ll sum=0;
    while(x)
        (sum+=s[id][x])%=mod,x-=x&-x;
    return (sum+mod)%mod;
}
ll query(int id,int l,int r)
{
    return ask(id,r)-ask(id,l);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",x+i,y+i);
        (s[0][i]+=x[i]*x[i]%mod+s[0][i-1])%=mod;
        (s[1][i]+=y[i]*y[i]%mod+s[1][i-1])%=mod;
        (s[2][i]+=x[i]*y[i]%mod+s[2][i-1])%=mod;
    }
    for(int i=n;i;i--)
    {
        s[0][i]-=s[0][i-(i&-i)];
        s[1][i]-=s[1][i-(i&-i)];
        s[2][i]-=s[2][i-(i&-i)];
    }
    ll x0,y0;
    for(int op,p,l,r,i=1;i<=m;i++)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%lld%lld",&p,&x0,&y0);
            change(0,p,(x0*x0-x[p]*x[p])%mod);
            change(1,p,(y0*y0-y[p]*y[p])%mod);
            change(2,p,(x0*y0-x[p]*y[p])%mod);
            x[p]=x0,y[p]=y0;
        }
        else
        {
            scanf("%d%d",&l,&r);
            ll c1=query(0,l-1,r),c2=query(1,l-1,r),c3=query(2,l-1,r);
            printf("%lld
",((c1*c2%mod-(c3*c3)%mod)%mod+mod)%mod);
        }
    }
    return 0;
}

2018.10.19