P1856 [USACO5.5]矩形周長Picture 題解
阿新 • • 發佈:2020-11-01
Link
Solve
這道題也是非常經典的掃描線問題,我們把圖形分成幾塊,每次就需要累加這一次的答案和上一次的答案的差就好了
然後橫著刷一遍,豎著刷一遍就好了
有些細節要注意,就是要在同一層的線,要先加邊後刪邊
Code
#include <iostream> #include <algorithm> #include <stdio.h> #include <math.h> using namespace std; typedef long long LL; int tree[80020],lazy[80020],cnt[80020]; #define ls nod<<1 #define rs nod<<1|1 void pushdown(int nod,int l,int r){ if(lazy[nod]){ lazy[ls]+=lazy[nod];cnt[ls]+=lazy[nod]; lazy[rs]+=lazy[nod];cnt[rs]+=lazy[nod]; lazy[nod]=0; } } void pushup(int nod,int l,int r){ if(cnt[ls]==cnt[rs]){cnt[nod]=cnt[ls];tree[nod]=tree[ls]+tree[rs];} else if(cnt[ls]<cnt[rs]){cnt[nod]=cnt[ls];tree[nod]=tree[ls];} else{cnt[nod]=cnt[rs];tree[nod]=tree[rs];} } void build(int nod,int l,int r){ lazy[nod]=0; if(l==r){cnt[nod]=lazy[nod]=0;tree[nod]=1;return;} int mid=l+r>>1; build(ls,l,mid);build(rs,mid+1,r); pushup(nod,l,r); } void ins(int nod,int l,int r,int x,int y,int v){ if(l==x&&r==y){ lazy[nod]+=v; cnt[nod]+=v; return; } pushdown(nod,l,r); int mid=l+r>>1; if(y<=mid)ins(ls,l,mid,x,y,v); else if(x>mid)ins(rs,mid+1,r,x,y,v); else{ins(ls,l,mid,x,mid,v);ins(rs,mid+1,r,mid+1,y,v);} pushup(nod,l,r); } int n;LL x,ans; struct bar{int a,b,c,d;bar(){}bar(int w,int x,int y,int z){a=w;b=x;c=y;d=z;}}b[5003],c[20003]; bool operator<(bar a,bar b){return a.a!=b.a?a.a<b.a:a.d>b.d;} void doit(){ sort(c+1,c+2*n+1);build(1,1,20002); for(int i=1;i<=n+n;i++){ x=tree[1]*(cnt[1]==0); ins(1,1,20002,c[i].b,c[i].c,c[i].d); ans+=abs(x-tree[1]*(cnt[1]==0)); } } int main(){ freopen("P5490.in","r",stdin); freopen("P5490.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d%d%d",&b[i].a,&b[i].b,&b[i].c,&b[i].d); b[i].a+=10001;b[i].b+=10001;b[i].c+=10001;b[i].d+=10001; c[2*i-1]=bar(b[i].b,b[i].a,b[i].c-1,1); c[2*i]=bar(b[i].d,b[i].a,b[i].c-1,-1); } doit(); for(int i=1;i<=n;i++){ c[2*i-1]=bar(b[i].a,b[i].b,b[i].d-1,1); c[2*i]=bar(b[i].c,b[i].b,b[i].d-1,-1); } doit(); printf("%lld",ans); return 0; }