题目链接<http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=2284>
题意:
在一个n*m的矩形中,每次会长长度为1的草。有k个UFO降临,会把严格在圆形范围内的草割光。问最后地面上还剩多少的草。
1<=n,m<=1e5,1<=k<=100
题解:
对于圆的面积,只能考虑每一行被覆盖的长度,然后累加。
这样,对于每一行,把每个UFO拆成左右两个点,记录点的位置,是左端点还是右端点,是第几个UFO。
把这一行的点丢进优先队列(不能用set,这样会tle)(不能开n个队列,这样会mle)。然后从左到右扫一遍队列,再开一个set维护最后面来的UFO,并计算答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
struct Node{
int p,f,id;
bool operator<(const Node k)const{
return p==k.p?id<k.id:p>k.p;
}
};
priority_queue<Node>q;
set<int,greater<int> >st;
int y[N],x[N],r[N];
int main(){
int n,m,k;
scanf("%d%d",&n,&m);
scanf("%d",&k);
for(int i=1;i<=k;i++){
scanf("%d%d%d",&y[i],&x[i],&r[i]);
}
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
int lo=y[j]-r[j];
int hi=y[j]+r[j];
if(hi<i||lo>i) continue;
int tt=(int)floor(sqrt(1ll*r[j]*r[j]-1ll*(i-y[j])*(i-y[j])));
q.push((Node){x[j]-tt,1,j});
q.push((Node){x[j]+tt+1,-1,j});
}
int tmp=1;
while(!q.empty()){
Node t=q.top();q.pop();
if(t.f==1){
if(st.empty()){
ans+=1ll*(t.p-tmp)*k;
tmp=t.p;
}
else if(t.id>*st.begin()){
ans+=1ll*(t.p-tmp)*(k-*st.begin());
tmp=t.p;
}
st.insert(t.id);
}
else{
if(*st.begin()==t.id){
ans+=1ll*(t.p-tmp)*(k-*st.begin());
tmp=t.p;
}
st.erase(t.id);
}
}
ans+=1ll*(m-tmp+1)*k;
}
printf("%lld\n",ans);
}