zoukankan      html  css  js  c++  java
  • 扫描线 && 洛谷 P5490 【模板】扫描线(线段树)

    传送门


    扫描线

    什么是扫描线?

    在一个二维平面上有许多的点,那一根水平或者竖直的直线将其切割。

    用途?

    降维。
    可以把二维问题转变成一维处理。
    解决许多数据结构问题。
    lxl的重要思路:一维问题--->二维平面--->扫描线降维。

    应用条件?

    离线。

    实现?

    线段树或者树状数组。
    树状数组常数比较小所以:区间修改单点查询可以改成单点修改区间查询问题-->树状数组实现。
    但是这个题因为是区间修改区间查询所以用线段树。

    注意事项?

    线段树一定要开足够大小。
    应手算一下,有时开四倍空间是不够的(例如本题需要开六倍)。
    建议动态开点。

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int maxn=4e5+5;
    struct node{
    	int x,xx,y,v;
    }a[maxn];
    struct Node{
    	long long len;
    	int v,l,r;
    }d[maxn*6];
    int n,m,b[maxn],cnt;
    long long ans;
    bool cmp(node a,node b){
    	return a.y<b.y;
    }
    void pushup(int id){
    	if(d[id].v) d[id].len=b[d[id].r+1]-b[d[id].l];
    	else d[id].len=d[id*2].len+d[id*2+1].len;
    }
    void build(int id,int l,int r){
    	d[id].l=l;
    	d[id].r=r;
    	if(l==r) return;
    	int mid=(l+r)/2;
    	build(id*2,l,mid);
    	build(id*2+1,mid+1,r);
    }
    void update(int id,int l,int r,int x,int y,int v){
    	if(x<=l&&r<=y){
    		d[id].v+=v;
    		pushup(id);
    		return;
    	}
    	int mid=(l+r)/2;
    	if(x<=mid) update(id*2,l,mid,x,y,v);
    	if(y>mid) update(id*2+1,mid+1,r,x,y,v);
    	pushup(id);
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		cin>>a[i].x>>a[i].y>>a[i+n].xx>>a[i+n].y;
    		a[i].xx=a[i+n].xx;
    		a[i+n].x=a[i].x;
    		a[i].v=1;
    		a[i+n].v=-1;
    		b[++cnt]=a[i].x;
    		b[++cnt]=a[i].y;
    		b[++cnt]=a[i+n].xx;
    		b[++cnt]=a[i+n].y;
    	}
    	sort(b+1,b+cnt+1);
    	m=unique(b+1,b+cnt+1)-b-1;
    	for(int i=1;i<=n;i++){
    		a[i].x=lower_bound(b+1,b+m+1,a[i].x)-b;
    		a[i].y=lower_bound(b+1,b+m+1,a[i].y)-b;
    		a[i].xx=lower_bound(b+1,b+m+1,a[i].xx)-b;
    		a[i+n].y=lower_bound(b+1,b+m+1,a[i+n].y)-b;
    		a[i+n].x=a[i].x;
    		a[i+n].xx=a[i].xx;
    	}
    	sort(a+1,a+2*n+1,cmp);
    	build(1,1,m);
    	for(int i=1;i<=2*n;i++){
    		ans+=1ll*(b[a[i].y]-b[a[i-1].y])*d[1].len;
    		update(1,1,m,a[i].x,a[i].xx-1,a[i].v);
    	}
    	cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    Web 跨域请求(OCRS) 前端解决方案
    接口与抽象
    观察者模式
    建造者模式(Builder)
    外观设计模式 (Facade)
    模板方法模式( TemplateMethod)
    原型模式(ProtoType)
    简单工厂法( Factory Method)
    backup与recover
    Oracle自动备份脚本的实现
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15270824.html
Copyright © 2011-2022 走看看