BZOJ 1818: [Cqoi2010]内部白点 【扫描线+树状数组】

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/88878821

题目传送门

题目分析:

应该很容易发现颜色改变只会在第一秒发生,不会有-1的情况。
实际上就是求线段的交点数量,去掉在端点相交的情况。
把y离散化,按x轴做扫描线,遇到一条横着的线段的左端点就在树状数组中对应的y位置+1,遇到右端点-1。对竖着的线段在树状数组中查询即可。

Code:

#include<cstdio>
#include<vector>
#include<cctype>
#include<cstring>
#include<algorithm>
#define maxn 100005
using namespace std;
char cb[1<<15],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
	char c;bool f=0;while(!isdigit(c=getc())) if(c=='-') f=1;
	for(a=c-'0';isdigit(c=getc());a=a*10+c-'0'); if(f) a=-a;
}
int n,tx[maxn],ty[maxn],ans;
vector<int>add[maxn],rec[maxn];//add reduce
struct node{
	int x,y;
}a[maxn];
bool cmpy(const node &a,const node &b){return a.y==b.y?a.x<b.x:a.y<b.y;}
bool cmpx(const node &a,const node &b){return a.x==b.x?a.y<b.y:a.x<b.x;}
int arr[maxn];
void upd(int i,int d){for(;i<=n;i+=i&-i) arr[i]+=d;}
int qsum(int i){int s=0;for(;i;i-=i&-i) s+=arr[i];return s;}
int main()
{
	read(n);
	for(int i=1;i<=n;i++) read(a[i].x),read(a[i].y),tx[i]=a[i].x,ty[i]=a[i].y;
	sort(tx+1,tx+1+n),sort(ty+1,ty+1+n);
	int lx=unique(tx+1,tx+1+n)-tx-1,ly=unique(ty+1,ty+1+n)-ty-1;
	for(int i=1;i<=n;i++) 
		a[i].x=lower_bound(tx+1,tx+1+lx,a[i].x)-tx,
		a[i].y=lower_bound(ty+1,ty+1+ly,a[i].y)-ty;
	sort(a+1,a+1+n,cmpy);
	for(int i=1,j;i<=n;i=j){
		for(j=i+1;a[j].y==a[i].y;j++);//把横着的线段的加减操作放到vector里面
		if(a[j-1].x-a[i].x>1) add[a[i].x].push_back(a[i].y),rec[a[j-1].x].push_back(a[i].y);
		//连续的线段可以只存最左和最右,查询的时候分段查询就可以避开交点。
	}
	sort(a+1,a+1+n,cmpx);
	for(int i=1,j=1,k;i<=n&&j<=n;i++,j=k){
		for(int o=rec[i].size()-1;o>=0;o--) upd(rec[i][o],-1);
		for(k=j+1;k<=n&&a[k].x==a[j].x;k++) if(a[k].y-a[k-1].y>1) ans+=qsum(a[k].y-1)-qsum(a[k-1].y);
		for(int o=add[i].size()-1;o>=0;o--) upd(add[i][o],1);
	}
	printf("%d",n+ans);
}

猜你喜欢

转载自blog.csdn.net/C20181220_xiang_m_y/article/details/88878821