SGU512

17 篇文章 0 订阅
15 篇文章 0 订阅

题目大意:

给出那个点

求这样的点对个数:以两点连线为对角线的矩形内不存在其他点(也不能在边界上)

首先注意到:对于某一个点p,我们考虑y值大于等于p的其他点

那么可行的点若在p的左边,y值一定单调递增,在右边则单调递减

我们只考虑左边的(右边的可以通过坐标变换变到左边来)

那么用树状数组套单调队列,可以维护一段单调的y值,

另外就是单调队列的合并问题:

树状数组不断往回跳的时候,会碰到两个单调队列的合并,这个比较好做……不详细写了……

然后还有算重的问题,在一开始减掉就行了

第一次写数据结构套数据结构的题……

pty的做法是开了一个大数组,我由于有把数据结构写成类的“良好习惯”

所以不太好这么做,于是我把树状数组的每个节点开成了个deque……

导致的结果是pty234ms,我1.4s+……常数巨大……本来写这种做法而不是分治就是为了节省常数的说……

嗯……详见代码好了……自认为写的比较好看……

PS:我wa6wa了很久,原因是因为我减去算重的部分的时候0那个位置没有开哨兵……就是没有赋成无穷……我自己怎么拍也拍不出来……sgu数据太强了……

另外,由于我在struct里开了10w个deque,3.x的g++貌似编译不过……反正我dev c++各种蛋疼……

code:

//Lib
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
//Macro
#define	rep(i,a,b)	for(int i=a,tt=b;i<=tt;++i)
#define	drep(i,a,b)	for(int i=a,tt=b;i>=tt;--i)
#define	erep(i,e,x)	for(int i=x;i;i=e[i].next)
#define	irep(i,x)	for(__typeof(x.begin()) i=x.begin();i!=x.end();i++)
#define	read()	(strtol(ipos,&ipos,10))
#define	sqr(x)	((x)*(x))
#define	pb	push_back
#define	PS	system("pause");
typedef	long long	ll;
typedef	pair<int,int>	pii;
const int oo=~0U>>1;
const double inf=1e100;
const double eps=1e-6;
string name="love", in=".in", out=".out";
//Var
int n,cnt;
long long ans;
int lisan[100008];
struct P
{
	int x,y;
	bool operator <(const P &o)const{return y>o.y||y==o.y&&x<o.x;};	
	bool operator ==(const P &o)const{return x==o.x&&y==o.y;}
}p[100008];
struct MQ
{
	deque<pii> q;
	void Insert(int x,int y)
	{
		while(!q.empty()&&q.front().second<=x)q.pop_front();
		q.push_front(pii(y,x));
	}
	int Union(int x)
	{
		return lower_bound(q.begin(),q.end(),pii(x,0))-q.begin()-1;
	}
};
struct TA
{
	MQ q[100008];
	void set(){rep(i,1,cnt)q[i].q.clear();}
	inline int lowbit(int x){return x&-x;}
	int Query(int x)
	{
		int ret=0,pos,now=oo;
		for(int i=x;i>0;i-=lowbit(i))
		{
			if(q[i].q.empty())continue;
			pos=q[i].Union(now);
			if(pos==-1)continue;
			ret+=pos+1;
			now=q[i].q[0].first;
		}
		return ret;
	}
	void Insert(int x,int y)
	{
		for(int i=x;i<=cnt;i+=lowbit(i))
			q[i].Insert(x,y);	
	}
}T;
void Init()
{
	scanf("%d",&n);
	set<int> s;
	rep(i,1,n)
	{
		scanf("%d%d",&p[i].x,&p[i].y);
		if(!s.insert(p[i].x).second)ans--;
	}
	sort(p+1,p+1+n);p[0].y=-oo;
	rep(i,1,n)if(p[i].y==p[i-1].y)ans--;
	irep(i,s)lisan[++cnt]=*i;
	rep(i,1,n)p[i].x=lower_bound(lisan+1,lisan+1+cnt,p[i].x)-lisan;
}
int Calc(P &x)
{
	int ret=T.Query(x.x);
	T.Insert(x.x,x.y);
	return ret;
}
void Work()
{
	rep(i,1,n)ans+=Calc(p[i]);	
	rep(i,1,n)p[i].x=cnt-p[i].x+1;
	sort(p+1,p+1+n);
	T.set();
	rep(i,1,n)ans+=Calc(p[i]);
	cout<<ans<<endl;
}
int main()
{
//	freopen((name+in).c_str(),"r",stdin);
//	freopen((name+out).c_str(),"w",stdout);
	Init();
	Work();
//	PS;
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值