題目大意:找出平行於x,y軸邊的三角形面積的兩倍。
枚舉要n*n*n,超時,分析下,要兩條直角邊上對應應長度和的乘積,然後要前綴和處理。共有四種形態的三角形。原來想每種單獨做,但遇到矩形還要處理重合,就參考題解了。
1.將所有同一x或y的點用VECTOR連起來,並離散化和距離的前綴和。
2.枚舉每一個點xi,yi,如左上圖所示,四種形態的三角形面積.以y軸爲例分析,分爲上半部分和下半部分,前綴和的求法如上圖所示。同理針對x軸,左半部分和右半部分分別求出。
參考代碼:copy form洛谷題解
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
using namespace std;
typedef long long ll;
const int MAXN=100005;
const int MOD=1e9+7;
int n;
int mx,my;
pair<ll,ll> a[MAXN];
ll ls1[MAXN],ls2[MAXN],x[MAXN],y[MAXN];
vector<ll> vx[MAXN],vy[MAXN],sumx[MAXN],sumy[MAXN];
ll ans=0;
int main() {
cin>>n;
for (int i=1; i<=n; i++) {
cin>>a[i].first>>a[i].second;
ls1[i]=a[i].first;
ls2[i]=a[i].second;
}
//離散化
sort(ls1+1,ls1+1+n);
sort(ls2+1,ls2+1+n);
mx=unique(ls1+1,ls1+1+n)-ls1-1;
my=unique(ls2+1,ls2+1+n)-ls2-1;
for (int i=1; i<=n; i++)
x[i]=lower_bound(ls1+1,ls1+1+mx,a[i].first)-ls1;
for (int i=1; i<=n; i++)
y[i]=lower_bound(ls2+1,ls2+1+my,a[i].second)-ls2;
for (int i=1; i<=n; i++) { //數據範圍10^4,且要回到a[]去判斷點。
vx[x[i]].push_back(y[i]);
vy[y[i]].push_back(x[i]);
}
//處理前綴和 & 排序
for (int i=1; i<=mx; i++) {
sort(vx[i].begin(),vx[i].end());
ll sum=0;
sumx[i].push_back(0);//求xi-x0d的前綴和
for (int j=0; j<vx[i].size(); j++) {
sum+=ls2[vx[i][j]];
sumx[i].push_back(sum);
}
}
for (int i=1; i<=my; i++) {
sort(vy[i].begin(),vy[i].end());
ll sum=0;
sumy[i].push_back(0);
for (int j=0; j<vy[i].size(); j++) {
sum+=ls1[vy[i][j]];
sumy[i].push_back(sum);
}
}
for (int i=1; i<=n; i++) {
ll posx=lower_bound(vx[x[i]].begin(),vx[x[i]].end(),y[i])-vx[x[i]].begin();//點i在x值相同的一列中y值的排名
ll posy=lower_bound(vy[y[i]].begin(),vy[y[i]].end(),x[i])-vy[y[i]].begin();//點i在y值相同的一行中x值的排名
ll sz1=vx[x[i]].size();
//普通座標系,當前點下面的部分, 當前點上面的部分
ll tmpx=(posx*ls2[y[i]]-sumx[x[i]][posx])%MOD+(sumx[x[i]][sz1]-sumx[x[i]][posx+1]-(sz1-posx-1)*ls2[y[i]])%MOD;
ll sz2=vy[y[i]].size();
ll tmpy=(posy*ls1[x[i]]-sumy[y[i]][posy])%MOD+(sumy[y[i]][sz2]-sumy[y[i]][posy+1]-(sz2-posy-1)*ls1[x[i]])%MOD;
ans+=tmpx*tmpy;
ans%=MOD;
}
cout<<ans<<endl;
return 0;
}