luogu5193 炸弹 (扫描线)
就是求连通块的数量,可以维护一个斜着的扫描线,set里只保留在R范围内的点
然而怎么维护连通块呢。。
其实只需要向能够到的最靠左和最靠右的点连边就可以,剩下的点之前就已经连好了
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 #define MP make_pair 5 #define fi first 6 #define se second 7 using namespace std; 8 typedef long long ll; 9 typedef unsigned long long ull; 10 typedef unsigned int ui; 11 typedef long double ld; 12 const int maxn=1e5+10; 13 14 inline char gc(){ 15 return getchar(); 16 static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf; 17 return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++; 18 } 19 inline ll rd(){ 20 ll x=0;char c=gc();bool neg=0; 21 while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();} 22 while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc(); 23 return neg?(~x+1):x; 24 } 25 26 struct Node{ 27 int x,y; 28 }p[maxn]; 29 int N,R,fa[maxn]; 30 set<pa> st; 31 bool flag[maxn]; 32 33 inline bool cmp(Node a,Node b){return a.y-a.x>b.y-b.x;} 34 35 inline int getf(int x){return x==fa[x]?x:fa[x]=getf(fa[x]);} 36 37 inline void uni(int x,int y){ 38 x=getf(x),y=getf(y); 39 if(x!=y) fa[x]=y; 40 } 41 42 int main(){ 43 //freopen("","r",stdin); 44 N=rd();R=rd(); 45 for(int i=1;i<=N;i++) p[i].x=rd(),p[i].y=rd(); 46 for(int i=1;i<=N;i++) fa[i]=i; 47 sort(p+1,p+N+1,cmp); 48 for(int i=1,j=1;i<=N;i++){ 49 for(;j<i&&(p[j].y-p[j].x)-(p[i].y-p[i].x)>R;j++) st.erase(MP(p[j].x+p[j].y,j)); 50 if(i>1){ 51 set<pa>::iterator it=st.lower_bound(MP(p[i].x+p[i].y-R,0)); 52 if(it!=st.end()&&it->fi<=p[i].x+p[i].y+R) uni(it->se,i); 53 it=st.upper_bound(MP(p[i].x+p[i].y+R,N)); 54 if(it!=st.begin()){ 55 --it; 56 if(it->fi>=p[i].x+p[i].y-R) uni(it->se,i); 57 } 58 } 59 60 st.insert(MP(p[i].x+p[i].y,i)); 61 } 62 int ans=0; 63 for(int i=1;i<=N;i++){ 64 if(!flag[getf(i)]) ans++; 65 flag[getf(i)]=1; 66 } 67 printf("%d\n",ans); 68 return 0; 69 }