【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]);
}
}
标签:cnt,组十连测,day7,sum,2021,扫描线,左上,复杂度
From: https://www.cnblogs.com/liyixin0514/p/18435594