Codeforces 610D Vika and Segments
题目大意:给你n(n<=1e9)条垂直于x轴或者与x轴平行的线,问你这些线占了多少个点。
写的时候感觉就是一道线段树,可是想不出来,后来题解说可以转化成面积问题,就知道
怎么写了,是一道线段树加扫描线求面积并的问题。
思路:将一条线转化为宽度为1的矩形,然后用线段树+扫描线+离散化求面积并就行了,
顺便帮我复习了一下扫描线。。 以后要多想想怎么转化不能这么菜了!!!!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define ll long long using namespace std; const int N=2*1e5+3; struct line { int x,y1,y2,op; bool operator < (const line &t)const { if(x==t.x) return op<t.op; return x<t.x; } }e[N]; int n,y[N],tot=0,cnt=0; int seg[N<<2],cover[N<<2]; //seg[i] 表示i这个区域内的覆盖长度,cover表示覆盖了几次。 void push_up(int rt,int l,int r,int op) { if(cover[rt]>=1) seg[rt]=y[r+1]-y[l]; else if(l==r) { if(op==1) seg[rt]=y[r+1]-y[l]; else seg[rt]=0; } else seg[rt]=seg[rt<<1]+seg[rt<<1|1]; } void updata(int L,int R,int l,int r,int rt,int g) { if(l>=L && r<=R) { cover[rt]+=g; push_up(rt,l,r,g); return; } int m=(l+r)>>1; if(L<=m) updata(L,R,lson,g); if(R>m) updata(L,R,rson,g); push_up(rt,l,r,g); } int main() { cin>>n; for(int i=1;i<=n;i++) { int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); if(y1>y2) swap(y1,y2),swap(x1,x2); if(y1==y2) { e[tot].x=x1; e[tot].y1=y1; e[tot++].y2=y1+1; e[tot].x=x2; e[tot].y1=y1; e[tot++].y2=y1+1; y[cnt++]=y1; y[cnt++]=y1+1; if(x1>x2) e[tot-2].x+=1,e[tot-1].op=1,e[tot-2].op=-1; else e[tot-1].x+=1,e[tot-2].op=1,e[tot-1].op=-1; } else { e[tot].x=x1; e[tot].op=1; e[tot].y1=y1; e[tot++].y2=y2+1; e[tot].x=x1+1; e[tot].op=-1; e[tot].y1=y1; e[tot++].y2=y2+1; y[cnt++]=y1; y[cnt++]=y2+1; if(x1>x2) e[tot-1].op=1,e[tot-2].op=-1; else e[tot-1].op=-1,e[tot-2].op=1; } } sort(y,y+cnt); sort(e,e+tot); cnt=unique(y,y+cnt)-y; ll ans=0,pre=-1e18; for(int i=0;i<tot;i++) { if(pre!=-1e18) ans+=(ll)(e[i].x-pre)*(ll)seg[1]; int up=lower_bound(y,y+cnt,e[i].y2)-y; int down=lower_bound(y,y+cnt,e[i].y1)-y; updata(down,up-1,0,tot-1,1,e[i].op); pre=e[i].x; } cout<<ans<<endl; return 0; }