题解 P6481 【[CRCI2006-2007] FIREFLY】
VioletIsMyLove · · 题解
当我们把脑袋向左旋转90°,把每一个石柱子看成一条线段,把枚举的高度看成一条竖线,唉呀妈呀这不就是传说中的扫描线吗?
此题的细节之处就是需要把高度抽象成一个小方格,换句话说就是把列看成是
Code:
#include<bits/stdc++.h>
#define maxh 500005
using namespace std;
int N,H,Ans,hight[maxh],Sum[maxh];
int read(){
int ret=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-')f=-f;ch=getchar();}
while (isdigit(ch)) ret=(ret<<3)+(ret<<1)+(ch&15),ch=getchar();
return ret*f;
}
int main(){
N=read(),H=read();
for (int i=1;i<=N;i++){
int x=read();
if (i&1) hight[1]++,hight[x+1]--;else hight[H-x+1]++,hight[H+1]--;
}
for (int i=1;i<=H;i++) Sum[i]=Sum[i-1]+hight[i];
sort(Sum+1,Sum+1+H);
for (int i=1;i<=H;i++)
if (Sum[i]==Sum[1]) Ans++;else break;
printf("%d %d\n",Sum[1],Ans);
return 0;
}
但换个角度思考,我们会发现这道题居然还可以用毛毛虫去做,解释在代码里。
Code:
//毛毛虫
#include <bits/stdc++.h>
#define maxn 200005
using namespace std;
int N,Ans,Ans_k,H,A[maxn],B[maxn];
int read(){
int f=1,ret=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f; ch=getchar();}
while( isdigit(ch)) ret=(ret<<3)+(ret<<1)+(ch&15),ch=getchar();
return f*ret;
}
int main(){
Ans=N=read(),H=read();
for(int i=1;i<=N;i++)
if(i&1) A[i+1>>1]=read(); //石笋
else B[i+1>>1]=read(); //石钟乳
sort(A+1,A+(N>>1)+1);
sort(B+1,B+(N>>1)+1);
int A_l=1,B_l=(N>>1);
for(int i=1;i<=H;i++){
while(A[A_l]<i&&A_l<=(N>>1)) A_l++; //找到第一个需要灭了的石笋
while(H-B[B_l]<i&&B_l<=(N>>1)) B_l--; //找到第一个需要灭了的石钟乳
if(N-A_l-B_l+1==Ans) Ans_k++;
if(N-A_l-B_l+1< Ans) Ans=N-A_l-B_l+1,Ans_k=1;
}
printf("%d\n%d\n",Ans,Ans_k);
return 0;
}
我看到这道题有人写的题解是树状数组,其实我一开始也写的是树状数组,但后来自己一思考发现根本没有写树状数组的必要,题目中根本不需要修改数值,所以还不如写扫描线。最重要的是!!!树状数组时效要慢2倍。。。
树状数组Code:
#include<bits/stdc++.h>
using namespace std;
int n,h,minn,maxn;
int b[2000005],c[5000005];
void put(int x,int v){for(int i=x;i<=h;i+=i&-i)c[i]+=v;}
int get(int x){
int cnt=0;
for(int i=x;i;i-=i&-i)cnt+=c[i];
return cnt;
}
inline int read(){
int ret=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){ret=ret*10+ch-'0';ch=getchar();}
return ret*f;
}
int main(){
n=read();h=read();
for(int i=1;i<=n;i+=2){
int x=read(),y=read();
put(1,1);put(x+1,-1);put(h-y+1,1);
}
for(int i=1;i<=h;i++)b[i]=get(i);
sort(b+1,b+1+h);
for(int i=1;i<=h;i++){minn++;if(b[i]!=b[i+1])break;}
printf("%d %d\n",b[1],minn);
return 0;
}