E. Count The Rectangles (Educational Codeforces Round 68)

题目链接: http://codeforces.com/problemset/problem/1194/E
题意: 给你一些平行坐标轴的线段,不会有线段会互相覆盖,问这些线段组成多少个矩形?
思路: 我们可以从下往上扫平行于x轴的线段,找到第一条后,然后确定与这条线段垂直相交的线段有多少个点,交点位置顺便用树状数组记录起来,接着枚举y位置看是否有平行与x轴的线段与上面记录的线段有交点,用树状数组求交点个数cnt,则形成的矩形个数为(cnt-1)*cnt/2,
注意到达垂直x的线段另一个端点后记得将该位置的交点删除,避免重复计算
代码是搬题解的

#include
#define lowbit(x)   x & (-x)
using namespace std;
typedef long long ll;
const int N=5e3+10;
const int H=1e4+10;
vector<pair<int,int> >ax[H];
vector<pair<int,int> >ay[H];
int tree[H];
void add(int x,int val)
{
	while(x<H)
	{
		tree[x]+=val;
		x+=lowbit(x);
	}
}

int get(int x)
{
	int ans=0;
	while(x>0)
	{
		ans+=tree[x];
		x-=lowbit(x);
	}
	return ans;
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int x1,x2,y1,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		x1+=5001,x2+=5001,y1+=5001,y2+=5001;
		if(x1==x2)
		{
			ax[x1].push_back(make_pair(min(y1,y2),max(y1,y2)));
		}
		else
		{
			ay[y1].push_back(make_pair(min(x1,x2),max(x1,x2)));
		}
	}
	ll ans=0;
	//return 0;
	for(int y=1;y<H;y++)
	{

		for(auto s: ay[y])
		{
			memset(tree,0,sizeof tree);
			vector<int>tmp[H];
			int l=s.first,r=s.second;
			for(int x=l;x<=r;x++)
			{
				for(auto s2: ax[x])
				{
					if(s2.first<=y&&s2.second>y)
					{
						tmp[s2.second].push_back(x);
						add(x,1);
					}
				}
			}
			for(int y2=y+1;y2<H;y2++)
			{
				for(auto s2: ay[y2])
				{
					int cnt=get(s2.second)-get(s2.first-1);
					ans+=(cnt-1)*cnt/2;
				}

				for(auto x: tmp[y2])
				{
					add(x,-1);
				}
			}
		}
	}
	printf("%lld\n",ans);
	return 0;
}

你可能感兴趣的:(codeforces,搜索)