zoukankan      html  css  js  c++  java
  • 数据结构:线段树——扫描线模板(面积并,周长和)

    点击查看折叠代码块
    /*
    矩形面积
    */
    #include <bits/stdc++.h>
    
    #define ed end()
    #define bg begin()
    #define mkp make_pair
    #define pb push_back
    #define v(T) vector<T>
    #define all(x) x.bg,x.ed
    #define newline puts("")
    #define si(x) ((int)x.size())
    #define rep(i,n) for(int i=1;i<=n;++i)
    #define rrep(i,n) for(int i=0;i<n;++i)
    #define srep(i,s,t) for(int i=s;i<=t;++i)
    
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int maxn = 1e5+10;
    const int inf = 0x7f7f7f7f;
    const ll inf_ll = 1ll*inf*inf;
    const int Mod = 1e9+7;
    const double eps = 1e-7;
    
    
    struct _line{//从下往上扫
        int xl,xr,h,f;//xl扫描线的左端点,xr右端点,h线所在的纵坐标位置,f标记:是矩形的下边(1)还是上边(-1)
        _line(int a=0,int b=0,int c=0,int d=0):xl(a),xr(b),h(c),f(d){}
        bool operator <(const _line &t) const{ return h<t.h; }//按照y的从小到大排序
    }L[maxn<<1];
    
    int n,xl,yl,xr,yr;
    int x[maxn<<1]; //横坐标离散化
    int lazy[maxn<<3];
    ll tree[maxn<<3];
    ll ans = 0;
    
    void pushup(int l,int r,int rt){
    	if(lazy[rt]!=0){//表示被覆盖过
    		tree[rt]=x[r+1]-x[l];//更新区间长度
    	}
    	else{
            if(l == r) tree[rt] = 0;//这里需要注意,如果区间长度为1,不用合并
    		else tree[rt]=tree[rt<<1]+tree[rt<<1|1];//合并儿子信息
    	}
    }
    
    void build(int l,int r,int rt){
        lazy[rt] = 0;
        tree[rt] = 0;
        if( l == r ){
            return ;
        }
        int m=(l+r)>>1;
        build(l,m,rt<<1);
        build(m+1,r,rt<<1|1);
    }
    
    void update(int L,int R,int v,int l,int r,int rt){
        if(L<=l && r<=R){
            lazy[rt]+=v;
            pushup(l,r,rt);
            return ;
        }
        int m=(l+r)>>1;
        if(L<=m) update(L,R,v,l,m,rt<<1);
        if(R>m) update(L,R,v,m+1,r,rt<<1|1);
        pushup(l,r,rt);
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
        	scanf("%d%d%d%d",&xl,&yl,&xr,&yr);
            x[(i<<1)-1]=xl;
    		x[i<<1]=xr;
            L[(i<<1)-1]=_line(xl,xr,yl,1);//矩形的下边
    		L[i<<1]=_line(xl,xr,yr,-1);//矩形的上边
        }
        sort(x+1,x+2*n+1);//离散化
    	sort(L+1,L+2*n+1);
    
        // 总的区间 [1,ct] -> [1,ct-1]
        int ct=unique(x+1,x+2*n+1)-x-1;//去重,ct的个数表示横坐标的个数
    
        build(1,ct-1,1);//建树
        ans = 0;
        for (int i=1;i<=2*n;i++){
            // 待修改区间 [l,r] -> [l,r-1]
            int l = lower_bound(x+1,x+ct+1,L[i].xl)-x;
            int r = lower_bound(x+1,x+ct+1,L[i].xr)-x;
            
            ans+=1ll*tree[1]*(L[i].h-L[i-1].h);//先算面积,再修改
            update(l,r-1,L[i].f,1,ct-1,1);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
    /*
    矩形周长和
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=1e5+10;
    const int inf=0x3f3f3f3f;
    int n;
    int xl,yl,xr,yr;
    
    struct Tree{
    	int sum;//区间被线段完全覆盖过几次 
    	int num;//区间被多少条不相交的线段覆盖(比如,[1,2],[4,5]则为2,[1,3],[4,5]则为1(我习惯用闭区间),[1,4],[2,2],[4,4]也为1)
    	int len;//区间被覆盖的长度
    	int lflag;//区间左端点是否被覆盖
    	int rflag;//区间右端点是否被覆盖
    }tree[maxn<<1];
    
    struct _Line{
    	int h;//扫描线的高度
    	int l,r;//扫描线的左右端点位置
    	int flag;//出边或者入边标记 
    	_Line(int a=0,int b=0,int c=0,int d=0):l(a),r(b),h(c),flag(d){}
    	bool operator < (const _Line &rhs) const {
    		if(h==rhs.h) return flag>rhs.flag;
    		else return h<rhs.h;
    	}
    }L[maxn<<1];
    
    void pushup(int l,int r,int rt){
    	if(tree[rt].sum){//区间被完全覆盖过 
    		tree[rt].num=1;
    		tree[rt].len=r-l+1;
    		tree[rt].lflag=tree[rt].rflag=1;
    	}
    	else{//tree[rt].sum=0
    		if(l==r){//叶子结点
    			tree[rt].num=0;
    			tree[rt].len=0;
    			tree[rt].lflag=tree[rt].rflag=0;
    		}
    		else{//一般情况
    			tree[rt].num=tree[rt<<1].num+tree[rt<<1|1].num;
    			tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len;
    			if(tree[rt<<1].rflag && tree[rt<<1|1].lflag) tree[rt].num--;
    			tree[rt].lflag=tree[rt<<1].lflag;
    			tree[rt].rflag=tree[rt<<1|1].rflag;
    		}
    	}
    }
    
    void update(int v,int L,int R,int l,int r,int rt){
    	if(L<=l && r<=R){
    		tree[rt].sum+=v;
    		pushup(l,r,rt);
    		return ;
    	}
    	int m=(l+r)>>1;
    	if(L<=m) update(v,L,R,l,m,rt<<1);
    	if(R>m) update(v,L,R,m+1,r,rt<<1|1);
    	pushup(l,r,rt);
    }
    int X[maxn];
    int main(){
    	int xmax=-inf,xmin=inf;
    	while(~scanf("%d",&n)){
    		for (int i=1;i<=n;i++){
    			scanf("%d%d%d%d",&xl,&yl,&xr,&yr);
    			xmax=max(xmax,max(xl,xr));
    			xmin=min(xmin,min(xl,xr));
    			L[i*2-1]=_Line(xl,xr,yl,1);
    			L[i*2]=_Line(xl,xr,yr,-1);
    		}
    
    		if(xmin<=0){//最左边值小于等于0 
    			for (int i=1;i<=n*2;i++){
    				L[i].l=L[i].l+(-xmin)+1;
    				L[i].r=L[i].r+(-xmin)+1;
    			}
    			xmax+=(-xmin);
    		}
    		sort(L+1,L+n*2+1);
    		
    		int ans=0,pre=0;
    		for (int i=1;i<=2*n;i++){
    			update(L[i].flag,L[i].l,L[i].r-1,1,xmax,1);
    			ans+=abs(tree[1].len-pre);
    			pre=tree[1].len;
    			ans+=tree[1].num*2*(L[i+1].h-L[i].h);
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    你将不再是道具,而是成为人如其名的人
  • 相关阅读:
    第三次作业
    第二次作业
    第一次作业
    实验二
    第一次试验
    第五次作业
    第四次作业
    第三次作业
    第二次作业
    第一次作业
  • 原文地址:https://www.cnblogs.com/wsl-lld/p/13393491.html
Copyright © 2011-2022 走看看