原题: http://acm.zjnu.edu.cn/CLanguage/contests/1146/problems/1003.html
题意:
一个 的矩阵,初始全部为0。k秒钟,每秒一个 ,将符合 的所有点值变成0,不符合的点值加1。问k秒后所有点的值之和。
解析:
从后往前维护,第k秒的区间变成0,第k-1秒的区间除了已经被包含的区间以外变成1,依次类推。将一个区间分成多条线,用set维护一下这个线即可。
麻烦的地方在这是一个圆,需要计算每条线的起点和长度就变得比较麻烦。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(register int i=a;i<=b;i++)
#define debug(i) printf("->%d\n",i)
const int maxn=109,maxm=2e5+5;
int x[maxn],y[maxn],r[maxn];
struct node{
int y1,y2;
node(){}
node(int y1,int y2):y1(y1),y2(y2){}
bool operator<(const node &r)const{
return y2<r.y2;
}
};
set<node>S[maxm];
LL ans=0;
node tmp;
void Push(int val,int idx,int y1,int y2){
tmp.y2=y1;
set<node>::iterator it=S[idx].lower_bound(tmp);
set<node>::iterator tmp=it;
if(it==S[idx].end() || (*it).y1>y2){
S[idx].insert(node(y1,y2));
ans-=(LL)val*(LL)(y2-y1+1);
return;
}
int l=min(y1,(*it).y1),r=y2;
int old=0;
int needcut=0;
while(it!=S[idx].end() && (*it).y1<=y2){
r=max(r,(*it).y2);
old+=(*it).y2-(*it).y1+1;
needcut++;
it++;
}
ans-=(LL)val*(LL)(r-l+1-old);
while(needcut--){
S[idx].erase(tmp++);
}
S[idx].insert(node(l,r));
}
inline judge(int x,int y,int x0,int y0,int r0){
return (x-x0)*(x-x0)+(y-y0)*(y-y0)<=r0*r0;
}
int main(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
ans=(LL)n*(LL)m*(LL)k;
for(int i=1;i<=k;i++){
scanf("%d%d%d",x+i,y+i,r+i);
}
int idx,y1,y2,X,Y;
for(int i=k;i>=1;i--){
X=x[i],Y=y[i]-r[i];
while(1){
idx=X+Y,y1=Y,y2=y[i]+(X-x[i]);
Push(i,idx,y1,y2);
if(X!=x[i]&&!judge(X-1,Y-1,x[i],y[i],r[i])){
int toX=2*x[i]-X,toY=Y;
idx=toX+toY;
y1=toY,y2=y[i]+(toX-x[i]);
Push(i,idx,y1,y2);
}
if(Y!=y[i]&&!judge(X+1,Y+1,x[i],y[i],r[i])){
int toX=X,toY=2*y[i]-Y;
idx=toX+toY;
y1=toY,y2=y[i]+(toX-x[i]);
Push(i,idx,y1,y2);
}
if(X==x[i]+r[i]&&Y==y[i])break;
if(judge(X+1,Y,x[i],y[i],r[i])){
X++;
}
else{
Y++;
}
}
}
printf("%lld\n",ans);
}