标签:注意 网格 经典 sample sort 水平线 log pre 黑点
题目看起来吓人且鬼畜,但是其实答案过了1s之后就不会变了;
这个可以画一下图,如果某个方向缺了一个点,导致他不能变黑的话,那么这个方向上也不可能有点变黑了,从而他也不可能变黑,所以在1s之后答案确定;
那么接下的问题就是一个扫描线的经典问题了,由于我们在计数的时候不能把原来的黑点也算进去,所以我们取横竖线段的时候要两两断开;
扫描线的具体做法是,通过sort求出所有横线和竖线,然后把竖线拆为两条,从下往上扫描,
遇到竖线的下端点就给该竖线的横坐标+1,遇到上端点就-1,然后遇到横线就查询一下横坐标范围内的权值和;
通过树状数组实现单点修改和区间查询,注意在纵坐标相同时,优先级为撤销>查询>添加;
//MADE BY QT666 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N=500050; int n,hsh[N],tot,tmp; struct data{ int x,y; }g[N]; bool cmp1(const data &a,const data &b){ if(a.x==b.x) return a.y<b.y; else return a.x<b.x; } bool cmp2(const data &a,const data &b){ if(a.y==b.y) return a.x<b.x; else return a.y<b.y; } struct date{ int l,r,x,y,op; }q[N]; int find(int x){return lower_bound(hsh+1,hsh+1+tot,x)-hsh;} bool cmp3(const date &a,const date &b){ if(a.y==b.y) return a.op<b.op; else return a.y<b.y; } int tr[N]; int lowbit(int x){return x&-x;} void update(int x,int v){ for(int i=x;i<=tot;i+=lowbit(i)) tr[i]+=v; } int query(int x){ int ret=0;if(x==0) return 0; for(int i=x;i;i-=lowbit(i)) ret+=tr[i]; return ret; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d",&g[i].x,&g[i].y); hsh[++tot]=g[i].x; } sort(hsh+1,hsh+1+tot);tot=unique(hsh+1,hsh+1+tot)-hsh-1; sort(g+1,g+1+n,cmp1); for(int i=2;i<=n;i++){ if(g[i].x==g[i-1].x){ tmp++;q[tmp].x=find(g[i-1].x),q[tmp].y=g[i-1].y,q[tmp].op=1; tmp++;q[tmp].x=find(g[i].x),q[tmp].y=g[i].y,q[tmp].op=-1; } } sort(g+1,g+1+n,cmp2); for(int i=2;i<=n;i++){ if(g[i].y==g[i-1].y){ tmp++;q[tmp].l=find(g[i-1].x),q[tmp].r=find(g[i].x),q[tmp].y=g[i].y,q[tmp].op=0; } } sort(q+1,q+1+tmp,cmp3);int sum=0; for(int i=1;i<=tmp;i++){ if(q[i].op==1) update(q[i].x,1); if(q[i].op==-1) update(q[i].x,-1); if(q[i].op==0) sum+=query(q[i].r-1)-query(q[i].l); } printf("%d\n",sum+n); return 0; }
标签:注意 网格 经典 sample sort 水平线 log pre 黑点
原文地址:http://www.cnblogs.com/qt666/p/7662234.html