P6149 [USACO20FEB]Triangles S--离散化+前缀和

题目大意:找出平行于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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值