BZOJ 1818: [Cqoi2010]内部白点
Posted 北屿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1818: [Cqoi2010]内部白点相关的知识,希望对你有一定的参考价值。
Description
如果一个点左右上下都有黑点,那么这个点也会变成黑点,问最后有多少个黑点\(n\leqslant 10^5\).
Solution
扫描线.
显然变化后的点并不会产生新点,因为他的产生就需要他上下左右有点。
可以把他们转化成一些横纵的互不相交的直线...然后求交点个数...就是扫描线...
Code
/************************************************************** Problem: 1818 User: BeiYu Language: C++ Result: Accepted Time:1672 ms Memory:16532 kb ****************************************************************/ #include <bits/stdc++.h> using namespace std; const int N = 300050; inline int in(int x=0,char s=getchar(),int v=1) { while(s>‘9‘||s<‘0‘)v=s==‘-‘?-1:v,s=getchar(); while(s>=‘0‘&&s<=‘9‘)x=x*10+s-‘0‘,s=getchar();return x*v; } int n,cp,cl,cy,ans; int yy[N]; pair<int,int> pp[N]; struct P { int x,y,f; }p[N]; struct L { int x,y1,y2; }l[N]; int cmpp(const P &a,const P &b) { return a.x==b.x?a.f>b.f:a.x<b.x; } int cmpl(const L &a,const L &b) { return a.x<b.x; } void Add1(L a) { p[++cp]=(P) { a.y1,a.x,1 },p[++cp]=(P) { a.y2,a.x,-1 }; } void Add2(L a) { l[++cl]=a; } int Qy(int x) { return lower_bound(yy+1,yy+cy+1,x)-yy; } namespace Seg { int d[N<<2]; #define lc (o<<1) #define rc (o<<1|1) #define mid ((l+r)>>1) void Update(int o) { d[o]=d[lc]+d[rc]; } void Add(int o,int l,int r,int x,int v) { // cout<<o<<" "<<l<<" "<<r<<" "<<x<<" "<<v<<endl; if(l==r) { d[o]+=v;return; } if(x<=mid) Add(lc,l,mid,x,v); else Add(rc,mid+1,r,x,v); Update(o); } int Qur(int o,int l,int r,int L,int R) { // cout<<o<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<endl; if(L<=l && r<=R) return d[o]; int res=0; if(L<=mid) res+=Qur(lc,l,mid,L,R); if(R>mid) res+=Qur(rc,mid+1,r,L,R); return res; } }; int main() { n=in(); for(int i=1;i<=n;i++) { int x=in(),y=in(); pp[i]=make_pair(x,y); yy[++cy]=y,yy[++cy]=y-1,yy[++cy]=y+1; } sort(yy+1,yy+cy+1); cy=unique(yy+1,yy+cy+1)-yy-1; for(int i=1;i<=n;i++) pp[i].second=Qy(pp[i].second); sort(pp+1,pp+n+1); for(int i=1,j;i<=n;i=j+1) { for(j=i;j<=n && pp[i].first==pp[j+1].first;j++); for(int k=i;k<j;k++) Add2((L) { pp[k].first,pp[k].second+1,pp[k+1].second-1 }); } for(int i=1;i<=n;i++) swap(pp[i].first,pp[i].second); sort(pp+1,pp+n+1); for(int i=1,j;i<=n;i=j+1) { for(j=i;j<=n && pp[i].first==pp[j+1].first;j++); for(int k=i;k<j;k++) if(pp[k].second+1<=pp[k+1].second-1) Add1((L) { pp[k].first,pp[k].second+1,pp[k+1].second-1 }); } sort(p+1,p+cp+1,cmpp); sort(l+1,l+cl+1,cmpl); /* cout<<cp<<endl; for(int i=1;i<=cp;i++) cout<<p[i].x<<" "<<p[i].y<<" "<<p[i].f<<endl; cout<<cl<<endl; for(int i=1;i<=cl;i++) cout<<l[i].x<<" "<<l[i].y1<<" "<<l[i].y2<<endl;*/ for(int i=1,j,k=1;i<=cl;i=j+1) { for(;k<=cp&&(p[k].x<l[i].x||(p[k].x==l[i].x&&p[k].f>0));k++) Seg::Add(1,1,cy,p[k].y,p[k].f); for(j=i;j+1<=cl && l[i].x==l[j+1].x;j++); for(int t=i;t<=j;t++) ans+=Seg::Qur(1,1,cy,l[t].y1,l[t].y2); for(;k<=cp && p[k].x==l[i].x;k++) Seg::Add(1,1,cy,p[k].y,p[k].f); }printf("%d\n",ans+n); return 0; }
以上是关于BZOJ 1818: [Cqoi2010]内部白点的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1818[Cqoi2010]内部白点 扫描线+树状数组