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;
    }
    
    你将不再是道具,而是成为人如其名的人
  • 相关阅读:
    Two Sum II
    Subarray Sum
    Intersection of Two Arrays
    Reorder List
    Convert Sorted List to Binary Search Tree
    Remove Duplicates from Sorted List II
    Partition List
    Linked List Cycle II
    Sort List
    struts2结果跳转和参数获取
  • 原文地址:https://www.cnblogs.com/wsl-lld/p/13393491.html
Copyright © 2011-2022 走看看