【2021提高组十连测day7】a

【2021提高组十连测day7】a

题意:求每个点和其他所有点曼哈顿距离的平方之和。

形式化地,求 \(\sum_{j=1}^{n} (|x_i-x_j|+|y_i-y_j|)^2(1\le i \le n)\)

对于每个点,我们把其他点分成四部分:左上、左下、右上、右下。四个部分可以通过旋转整个坐标系来解决。因此这里讲如何处理左上的点。

左上的点满足 \(x_i\ge x_j,y_i>y_j\),因此式子变成 $\sum_{j=1}^{n} (x_i-x_j+y_i-y_j)^2=\sum_{j} (x_i+y_i)2+(x_j+y_j)2-2(x_i+y_i)(x_j+y_j)=cnt_{x_i,y_i}(x_i+y_i)^2-2(x_j+y_j)(\sum_{j} x_j+y_j)+\sum_{j} (x_j+y_j)^2 $。

因此我们只需要维护 \(cnt_{x_i,y_i}\) 表示点 \(i\) 左上的点的个数;\(sum_{x_i,y_i}\) 表示左上的点的 \(x_j+y_j\) 之和;\(ans_{x_i,y_i}\) 表示左上的点的 \(x_j+y_j\) 的平方之和。就可以 \(O(1)\) 求出答案了。

这是一个二维偏序问题,可以扫描线 + 树状数组做。

扫描线 \(x\) 从小到大扫描,树状数组以 \(y\) 为下标,需要离散化。详见代码。

时间复杂度 \(O(n\log n)\)

其实赛中我想到的是普通莫队,就是没想到旋转坐标系,分四类导致代码过于赤石,写了 2h 之后改去写暴力了。虽然但是我暴力也挂了 30pts

还是维护 \(cnt,sum,ans\),横坐标或者纵坐标转移一个单位通过预处理可以达到 \(O(1)\) 时间复杂度,因此可以莫队,时间复杂度 \(O\sqrt{n}\)。当然还是扫描线更好。

code

#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
using namespace std;
typedef long long ll;
const int N=1e5+7,mod=998244353;
ll add(ll a,ll b){
    return ((a+b)%mod+mod)%mod;
}
struct node{
    int id,x,y;
    ll sum,ans;
    void turn(){
        swap(x,y),y=-y;
        sum=add(x,y);
        ans=sum*sum%mod;
    }
}a[N];
int b[N];
int m;
int n;
int x,y;
bool cmp(node a,node b){
    return (a.x!=b.x?a.x<b.x:a.y<b.y);
}
struct Tree{
    int tr[N];
    void clear(){
        memset(tr,0,sizeof(tr));
    }
    void insert(int x,ll val){
        for(;x<=m;x+=x&-x) tr[x]=add(tr[x],val);
    }
    ll query(int x){
        ll s=0;
        for(;x;x-=x&-x) s=add(s,tr[x]);
        return s;
    }
}cnt,sum,ans;
int yy[N];
ll f[N];
void solve(){
    cnt.clear(),sum.clear(),ans.clear();
    rep(i,1,n) b[i]=a[i].y;
    sort(a+1,a+n+1,cmp);
    sort(b+1,b+n+1);
    m=unique(b+1,b+n+1)-b-1;
    rep(i,1,n) yy[i]=lower_bound(b+1,b+m+1,a[i].y)-b;
    rep(i,1,n){
        ll cntu=cnt.query(yy[i]-1),
        sumu=sum.query(yy[i]-1),
        ansu=ans.query(yy[i]-1);
        f[a[i].id]=add(f[a[i].id],(a[i].ans*cntu%mod+ansu-2ll*a[i].sum*sumu%mod)%mod);
        cnt.insert(yy[i],1ll),sum.insert(yy[i],a[i].sum),ans.insert(yy[i],a[i].ans);
    }
}
void turn(){
    rep(i,1,n){
        a[i].turn();
    }
}
int main(){
    // freopen("in.txt","r",stdin);
    // freopen("my.out","w",stdout);
    sf("%d",&n);
    rep(i,1,n){
        sf("%d%d",&x,&y);
        a[i]={i,x,y,add(x,y),1ll*add(x,y)*add(x,y)%mod};
    }
    rep(i,0,3){
        solve();
        turn();
    }
    rep(i,1,n){
        pf("%lld\n",f[i]);
    }
}
posted @ 2024-09-27 14:17  liyixin  阅读(5)  评论(0编辑  收藏  举报