1. 程式人生 > >天才紳士少女助手克里斯蒂娜 解題報告

天才紳士少女助手克里斯蒂娜 解題報告

天才紳士少女助手克里斯蒂娜

Description

紅莉棲想要弄清楚樓下天王寺大叔的映象管電視對 “電話微波爐 (暫定)” 的影響.

選取映象管的任意一個平面, 一開始平面內有個 \(n\) 電子, 初始速度分別為 \(v_i\), 定義飄升係數為\(\sum\limits_{1 \le i < j \le n}|\mathbb{v_i} \times \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\n",((c1*c2%mod-(c3*c3)%mod)%mod+mod)%mod);
        }
    }
    return 0;
}

2018.10.19