您的位置:首页 > 其它

bzoj3228 [ SDOI2008 ] -- 扫描线 + 线段树

2017-09-24 19:34 267 查看
首先曼哈顿距离有如下性质:

|x1−x2|+|y1−y2|=max(|x1−y1−(x2−y2)|,|x1+y1−(x2+y2)|)

于是将点 (x,y) 的坐标转化为 (x−y,x+y),点控制的范围就变成了一个正方形,扫描线+线段树即可。

注意转化后的坐标系中 x+y 为奇数的点是不存在的,所以线段树还要维护奇数的个数。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int& x){
char c=nc();
for(;c<'0'||c>'9';c=nc());
for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
#define N 100010
#define M 5000000
#define INF 200000000
#define ll long long
struct Line{
int w,f;
bool d;
}b[N<<1];
struct Node{
int x,y,w;
}a
;
long long Ans;
int i,j,k,n,m,t,num,T,cnt,c[M],C[M],cl[M],cr[M],p[M],L
,R
,Rt,m1,m2,M1,M2;
int d
;
inline bool Cmp(Line a,Line b){
return a.w<b.w;
}
inline void Update(int& x,int l,int r,int L,int R,int y){
if(l>R||r<L)return;
if(!x)x=++cnt;
if(l>=L&&r<=R){
p[x]+=y;
c[x]=(p[x]>0?r-l+1:c[cl[x]]+c[cr[x]]);
C[x]=(p[x]>0?(r-l+1>>1)+((l%2&&r%2)?1:0):C[cl[x]]+C[cr[x]]);
return;
}
int Mid=l+r>>1;
Update(cl[x],l,Mid,L,R,y);Update(cr[x],Mid+1,r,L,R,y);
c[x]=(p[x]>0?r-l+1:c[cl[x]]+c[cr[x]]);
C[x]=(p[x]>0?(r-l+1>>1)+((l%2&&r%2)?1:0):C[cl[x]]+C[cr[x]]);
}
inline bool Cmp1(Node a,Node b){
return a.y<b.y;
}
inline ll Get(int a,int b,int c,int d){
if(a>=b)return 0;
c=max(c,0);d=max(d,0);
if(a==b-1)return max(c,d-1);
if(!c&&!d)return 0;
if(!c)return d<b-a?1ll*d*(d-1)/2:1ll*(2*d-b+a-1)*(b-a)/2;
if(!d)return c<b-a?1ll*c*(c+1)/2:1ll*(2*c-b+a+1)*(b-a)/2;
if(c+d<=b-a+1)return 1ll*c*(c+1)/2+1ll*d*(d-1)/2;
int x=c-d+b-a>>1;
if(x<0)return 1ll*(2*d-b+a-1)*(b-a)/2;
if(x>=b-a-1)return 1ll*(2*c-b+a+1)*(b-a)/2;
if(x*2==c-d+b-a)return 1ll*(c*2-x+1)*x/2+1ll*(d*2-b+a+x-1)*(b-a-x)/2;
return 1ll*(c*2-x+1)*x/2+1ll*(d*2-b+a+x-1)*(b-a-x)/2+1;
}
inline void Solve1(){
sort(a+1,a+k+1,Cmp1);
d[k]=a[k].w-n+a[k].x-a[k].y;
for(i=k-1;i;i--)d[i]=max(d[i+1],a[i].w-n+a[i].x-a[i].y);
t=-INF;d[k+1]=-INF;a[0].y=M1;a[k+1].y=M2;
for(i=0;i<=k;i++){
if(i)t=max(t,a[i].w-n+a[i].x+a[i].y);
Ans-=Get(i?a[i].y:M1,i<k?a[i+1].y:M2,t-a[i].y,d[i+1]+a[i+1].y);
}
if(t-M2>0)Ans-=t-M2;
d[k]=a[k].w+1-a[k].x-a[k].y;
for(i=k-1;i;i--)d[i]=max(d[i+1],a[i].w+1-a[i].x-a[i].y);
t=-INF;
for(i=0;i<=k;i++){
if(i)t=max(t,a[i].w+1-a[i].x+a[i].y);
Ans-=Get(i?a[i].y:M1,i<k?a[i+1].y:M2,t-a[i].y,d[i+1]+a[i+1].y);
}
if(t-M2>0)Ans-=t-M2;
}
inline void Solve2(){
sort(a+1,a+k+1,Cmp1);
d[k]=a[k].w-n+a[k].x-a[k].y;
for(i=k-1;i;i--)d[i]=max(d[i+1],a[i].w-n+a[i].x-a[i].y);
t=-INF;d[k+1]=-INF;a[0].y=1;a[k+1].y=m;
for(i=0;i<=k;i++){
if(i)t=max(t,a[i].w-n+a[i].x+a[i].y);
Ans-=Get(i?a[i].y:1,i<k?a[i+1].y:m,t-a[i].y,d[i+1]+a[i+1].y);
}
if(t-m>0)Ans-=t-m;
d[k]=a[k].w+1-a[k].x-a[k].y;
for(i=k-1;i;i--)d[i]=max(d[i+1],a[i].w+1-a[i].x-a[i].y);
t=-INF;
for(i=0;i<=k;i++){
if(i)t=max(t,a[i].w+1-a[i].x+a[i].y);
Ans-=Get(i?a[i].y:1,i<k?a[i+1].y:m,t-a[i].y,d[i+1]+a[i+1].y);
}
if(t-m>0)Ans-=t-m;
}
int main(){
Read(n);Read(m);Read(k);
m1=M1=INF;m2=M2=-INF;
for(i=1;i<=k;i++){
Read(a[i].x);Read(a[i].y);Read(a[i].w);
a[i].w=min(a[i].w,INF);
M1=min(M1,a[i].y-a[i].w);M2=max(M2,a[i].y+a[i].w);
t=a[i].x,a[i].x-=a[i].y,a[i].y+=t;
L[i]=a[i].y-a[i].w;R[i]=a[i].y+a[i].w;
b[++num].f=i;b[num].w=a[i].x-a[i].w;
b[++num].f=i;b[num].w=a[i].x+a[i].w+1;b[num].d=1;
m1=min(m1,L[i]);m2=max(m2,R[i]);
}
sort(b+1,b+num+1,Cmp);
for(i=1;i<=num;i=j+1){
for(j=i;j<=num&&b[j+1].w==b[j].w;){
Update(Rt,m1,m2,L[b[j].f],R[b[j].f],b[j].d?-1:1);
j++;
}
if(j<=num)Update(Rt,m1,m2,L[b[j].f],R[b[j].f],b[j].d?-1:1);
if(j<num){
Ans+=1ll*(b[j+1].w-b[i].w)/2*c[Rt];
if(!(b[i].w%2)&&b[j+1].w%2)Ans+=c[Rt]-C[Rt];
if((b[i].w%2)&&!(b[j+1].w%2))Ans+=C[Rt];
}
}
for(i=1;i<=k;i++)t=a[i].x,a[i].x=a[i].x+a[i].y>>1,a[i].y=a[i].y-t>>1;
Solve1();
for(i=1;i<=k;i++)swap(a[i].x,a[i].y);
swap(n,m);
Solve2();
cout<<Ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: