BZOJ 1818 Cqoi2010 内部白点 树状数组

题目大意:给定平面上的一些黑点,其它位置都是白点,一个白点如果上下左右都有黑点就会变成黑点,求最终会有多少个黑点

语文题?

总之我们现在得到了一些横向和纵向的线段(注意线段不能包含两端点!),求出交点数后+n就是答案

我们可以将横向线段看做修改,纵向线段看做询问,那么一个询问可以拆成两个

然后我们离线做,将询问按y坐标排序,对于每个询问将y坐标小于等于这个询问的修改都加入树状数组,然后查询这个询问的x坐标即可

懒得离散化,第一次尝试用Hash表写树状数组,效果还不错= =

时间复杂度O(nlogn)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
struct Point{
	int x,y;
	friend istream& operator >> (istream &_,Point &p)
	{
		scanf("%d%d",&p.x,&p.y);
		p.x+=1000000007;
		p.y+=1000000007;
		return _;
	}
}points[M];
struct Interval{
	int l,r,y;
	Interval() {}
	Interval(int _,int __,int ___):
		l(_),r(__),y(___) {}
	bool operator < (const Interval &i) const
	{
		return y < i.y;
	}
}intervals[M],*I=intervals;
struct Query:Point{
	int flag;
	Query() {}
	Query(int _,int __,int ___):flag(___)
	{
		x=_;y=__;
	}
}queries[M<<1],*Q=queries;
int n;
long long ans;
bool Compare1(const Point &p1,const Point &p2)
{
	if(p1.x!=p2.x)
		return p1.x<p2.x;
	return p1.y<p2.y;
}
bool Compare2(const Point &p1,const Point &p2)
{
	if(p1.y!=p2.y)
		return p1.y<p2.y;
	return p1.x<p2.x;
}
namespace BIT{
	struct Hash_Set{
		struct List{
			int hash,val;
			List *next;
			List(int _,List *__):
				hash(_),val(0),next(__){}
		}*head[1001001];
		int& operator [] (int hash)
		{
			int pos=hash%1001001;
			List *temp;
			for(temp=head[pos];temp;temp=temp->next)
				if(temp->hash==hash)
					return temp->val;
			return (head[pos]=new List(hash,head[pos]))->val;
		}
	}c;
	void Update(int x,int y)
	{
		for(;x;x-=x&-x)
			c[x]+=y;
	}
	int Get_Ans(long long x)
	{
		int re=0;
		for(;x<=2000000007;x+=x&-x)
			re+=c[x];
		return re;
	}
}
int main()
{
	using namespace BIT;
	int i;
	cin>>n;
	for(i=1;i<=n;i++)
		cin>>points[i];
	sort(points+1,points+n+1,Compare2);
	for(i=2;i<=n;i++)
		if(points[i].y==points[i-1].y&&points[i].x>=points[i-1].x+2)
			new (I++)Interval(points[i-1].x+1,points[i].x-1,points[i].y);
	sort(points+1,points+n+1,Compare1);
	for(i=2;i<=n;i++)
		if(points[i].x==points[i-1].x&&points[i].y>=points[i-1].y+2)
		{
			new (Q++)Query(points[i].x,points[i-1].y,-1);
			new (Q++)Query(points[i].x,points[i].y-1,1);
		}
	sort(intervals,I);
	sort(queries,Q,Compare2);
	Interval *_i=intervals;
	Query *_q=queries;
	for(;_q<Q;_q++)
	{
		for(;_i<I&&_i->y<=_q->y;_i++)
			Update(_i->l-1,-1),Update(_i->r,1);
		ans+=Get_Ans(_q->x)*_q->flag;
	}
	cout<<ans+n<<endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值