Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
扫描线>做这道题我花了相当多的时间,一是由于自己的代码太长没有进行**模块化的编程**(例如求解水平和竖直周长的时候可以用相同的函数处理),二是我对**扫描线算法求解的问题特性**不够熟悉。 *** ## 题目分析 这道题很容易看出来是**扫描线算法**,因此建立扫描线和离散化处理就是非常自然的操作。但是之后有两点卡住了我: (1)扫描线算法处理的问题一般都有一个特性,那就是**正1扫描线和负1扫描线都是一一对应**的。因此对于线段树的每一个节点,我们都可以直接用**c数组**表示该节点代表区间被扫描线覆盖的次数。若c大于0,则直接得到区间全部被覆盖;若c=0,则区间覆盖值就是子区间覆盖长度之和。 (2)周长变化应该如何维护?我之前想要对每个单位长度的覆盖次数进行维护,但这样时间复杂度极高。其实只需要每次更新扫描线后将**abs(新覆盖长度-旧覆盖长度)加入到ans**里就行。需要注意的是,这道题默认重叠边的长度算入周长,是非常坑的一个点。如果不计入重叠边的话,应该需要在先对扫描线进行预处理。 ## 代码 #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int N=5001; struct line { int st,en; int pos; int val; bool operator <(const line &others)const { return pos<others.pos; } }v[N*2],h[N*2]; struct tree { int l,r; int val; int sum,c; }t[N*8]; int n; int ver[N*2],hor[N*2]; int hm,vm; int ans=0,init; void build(int p,int l,int r) { t[p].l=l; t[p].r=r; t[p].val=0; t[p].sum=0; t[p].c=0; if(l==r) { return; } int mid=(l+r)>>1; build(p*2,l,mid); build(p*2+1,mid+1,r); return; } void changeh(int p,int l,int r,int k) { if(t[p].l==t[p].r) { t[p].c+=k; if(t[p].c) { t[p].sum=hor[t[p].r+1]-hor[t[p].l]; } else { t[p].sum=0; } return; } if(t[p].l>=l && t[p].r<=r) { t[p].c+=k; if(t[p].c) { t[p].sum=hor[t[p].r+1]-hor[t[p].l]; } else { t[p].sum=t[p*2].sum+t[p*2+1].sum; } return; } int mid=(t[p].l+t[p].r)>>1; if(mid>=l) { changeh(p*2,l,r,k); } if(mid+1<=r) { changeh(p*2+1,l,r,k); } if(!t[p].c) { t[p].sum=t[p*2].sum+t[p*2+1].sum; } return; } void changev(int p,int l,int r,int k) { if(t[p].l==t[p].r) { t[p].c+=k; if(t[p].c) { t[p].sum=ver[t[p].r+1]-ver[t[p].l]; } else { t[p].sum=0; } return; } if(t[p].l>=l && t[p].r<=r) { t[p].c+=k; if(t[p].c) { t[p].sum=ver[t[p].r+1]-ver[t[p].l]; } else { t[p].sum=t[p*2].sum+t[p*2+1].sum; } return; } int mid=(t[p].l+t[p].r)>>1; if(mid>=l) { changev(p*2,l,r,k); } if(mid+1<=r) { changev(p*2+1,l,r,k); } if(!t[p].c) { t[p].sum=t[p*2].sum+t[p*2+1].sum; } return; } void pro() { sort(ver+1,ver+n*2+1); vm=unique(ver+1,ver+n*2+1)-ver-1; sort(hor+1,hor+n*2+1); hm=unique(hor+1,hor+n*2+1)-hor-1; return; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); ver[i*2-1]=a; ver[i*2]=c; hor[i*2-1]=b; hor[i*2]=d; v[i*2-1].st=b; v[i*2-1].en=d; v[i*2-1].pos=a; v[i*2-1].val=1; v[i*2].st=b; v[i*2].en=d; v[i*2].pos=c; v[i*2].val=-1; h[i*2-1].st=a; h[i*2-1].en=c; h[i*2-1].pos=b; h[i*2-1].val=1; h[i*2].st=a; h[i*2].en=c; h[i*2].pos=d; h[i*2].val=-1; } pro(); for(int i=1;i<=n;i++) { int a=h[i*2-1].st; int b=v[i*2-1].st; int c=h[i*2-1].en; int d=v[i*2-1].en; v[i*2-1].st=lower_bound(hor+1,hor+hm+1,b)-hor; v[i*2-1].en=lower_bound(hor+1,hor+hm+1,d)-hor; v[i*2-1].pos=lower_bound(ver+1,ver+vm+1,a)-ver; v[i*2-1].val=1; v[i*2].st=v[i*2-1].st; v[i*2].en=v[i*2-1].en; v[i*2].pos=lower_bound(ver+1,ver+vm+1,c)-ver; v[i*2].val=-1; h[i*2-1].st=lower_bound(ver+1,ver+vm+1,a)-ver; h[i*2-1].en=lower_bound(ver+1,ver+vm+1,c)-ver; h[i*2-1].pos=lower_bound(hor+1,hor+hm+1,b)-hor; h[i*2-1].val=1; h[i*2].st=h[i*2-1].st; h[i*2].en=h[i*2-1].en; h[i*2].pos=lower_bound(hor+1,hor+hm+1,d)-hor; h[i*2].val=-1; } sort(v+1,v+n*2+1); sort(h+1,h+n*2+1); //竖直方向的周长 build(1,1,hm-1); init=0; for(int i=1;i<=n*2;i++) { int st=v[i].st; int en=v[i].en-1; int op=v[i].val; changeh(1,st,en,op); ans+=abs(init-t[1].sum); init=t[1].sum; } //水平方向的周长 build(1,1,vm-1); init=0; for(int i=1;i<=n*2;i++) { int st=h[i].st; int en=h[i].en-1; int op=h[i].val; changev(1,st,en,op); ans+=abs(init-t[1].sum); init=t[1].sum; } printf("%d",ans); return 0; } Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator