线段树扫描线(周长并)hdu1828

每个线段树的节点要记录几个信息

1.l,r,该节点代表的线段的左右端点坐标

2.lp,rp,是一个标记量,只有0,1,表示这个节点左右两个端点没有被覆盖,有为1,无为0

3.cnt,表示这个区间被重复覆盖了几次

4.len,这个区间被覆盖的长度

5.num,这个区间被多少条线段覆盖

好像区间[0,10],被[1,2],[4,5]覆盖,那么num=2

好像区间[0,10],[1,3][4,5]覆盖,那么num=1,因为他们刚好连在一起了

好像区间[0,10],[1,5][2,6]覆盖,那么num=1,因为还是连起来的一段

 

前面的工作是相同的,把横线保存在一个表中,按竖直位置排序,然后从下往上扫描所有横线,在这个方法中,每次扫描一条横线,都能计算出两不部分值,一部分是横线的,一部分是竖线的

而计算横线部分的方法和第一种方法是一样的,即求出【现在这次总区间被覆盖的长度和上一次总区间被覆盖的长度的差的绝对值】,另外怎么算竖线部分呢?首先我们要知道添加了这条横线后会有多少条竖线,答案是2*num,所以为什么要记录num呢,因为总区间被num条线段覆盖,那么必定有2*num的端点,这些端点其实就是连着竖线,那么这些竖线的长度是多少呢?

就是【下一条横线的高度-现在这条横线的高度】,只要把这个高度乘上2*num即可


#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
 
const int maxn = 22222;
struct Seg{
	int l , r , h , s;
	Seg() {}
	Seg(int a,int b,int c,int d):l(a) , r(b) , h(c) , s(d) {}
	bool operator < (const Seg &cmp) const {
		if (h == cmp.h) return s > cmp.s;
		return h < cmp.h;
	}
}ss[maxn];
bool lbd[maxn<<2] , rbd[maxn<<2];
int numseg[maxn<<2];
int cnt[maxn<<2];
int len[maxn<<2];
void PushUP(int rt,int l,int r) {
	if (cnt[rt]) {
		lbd[rt] = rbd[rt] = 1;
		len[rt] = r - l + 1;
		numseg[rt] = 2;
	} else if (l == r) {
		len[rt] = numseg[rt] = lbd[rt] = rbd[rt] = 0;
	} else {
		lbd[rt] = lbd[rt<<1];
		rbd[rt] = rbd[rt<<1|1];
		len[rt] = len[rt<<1] + len[rt<<1|1];
		numseg[rt] = numseg[rt<<1] + numseg[rt<<1|1];
		if (lbd[rt<<1|1] && rbd[rt<<1]) numseg[rt] -= 2;//两条线重合
	}
}
void update(int L,int R,int c,int l,int r,int rt) {
	if (L <= l && r <= R) {
		cnt[rt] += c;
		PushUP(rt , l , r);
		return ;
	}
	int m = (l + r) >> 1;
	if (L <= m) update(L , R , c , lson);
	if (m < R) update(L , R , c , rson);
	PushUP(rt , l , r);
}
int main() {
	int n;
	while (~scanf("%d",&n)) {
		int m = 0;
		int lbd = 10000, rbd = -10000;
		for (int i = 0 ; i < n ; i ++) {
			int a , b , c , d;
			scanf("%d%d%d%d",&a,&b,&c,&d);
			lbd = min(lbd , a);
			rbd = max(rbd , c);
			ss[m++] = Seg(a , c , b , 1);
			ss[m++] = Seg(a , c , d , -1);
		}
		sort(ss , ss + m);
		int ret = 0 , last = 0;
		for (int i = 0 ; i < m ; i ++) {
			if (ss[i].l < ss[i].r) update(ss[i].l , ss[i].r - 1 , ss[i].s , lbd , rbd - 1 , 1);
			ret += numseg[1] * (ss[i+1].h - ss[i].h);
			ret += abs(len[1] - last);
			last = len[1];
		}
		printf("%d\n",ret);
	}
	return 0;
}

也可以二分,刚开始没初始化不对

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=88010;
struct seg
{
    int l,r,h,c;
    seg(){}
    seg(int a,int d,int b,int t):l(a),r(d),h(b),c(t){}
    bool operator < (const seg &a)const
    {
        if(h==a.h)return c>a.c;
        return h<a.h;
    }
}ss[maxn/4];
int X[maxn];
int n,num;
struct IntevalTree
{
    int cnt[maxn];
    int numseg[maxn];
    int sum[maxn];
    bool lbd[maxn],rbd[maxn];
    //IntevalTree(){}
    void init()
    {
        memset(cnt,0,sizeof(cnt));
        memset(numseg,0,sizeof(numseg));
        memset(sum,0,sizeof(sum));
        memset(lbd,0,sizeof(lbd));
        memset(rbd,0,sizeof(rbd));
    }
    void pushup(int o,int l,int r)
    {
        if(cnt[o])
        {
            lbd[o]=rbd[o]=1;
            sum[o]=X[r+1]-X[l];
            numseg[o]=2;
        }
        else if(l==r)
        {
            lbd[o]=rbd[o]=sum[o]=numseg[o]=0;
        }
        else
        {
            lbd[o]=lbd[o*2];rbd[o]=rbd[o*2+1];
            sum[o]=sum[o*2]+sum[o*2+1];
            numseg[o]=numseg[o*2]+numseg[o*2+1];
            if(lbd[o*2+1]&&rbd[o*2])numseg[o]-=2;
        }
    }
    void update(int o,int l,int r,int q1,int q2,int t)
    {
        if(q1<=l&&r<=q2)
        {
            cnt[o]+=t;
            pushup(o,l,r);
            return;
        }
        int mid=(l+r)/2;
        if(q1<=mid)update(o*2,l,mid,q1,q2,t);
        if(q2>mid)update(o*2+1,mid+1,r,q1,q2,t);
        pushup(o,l,r);
    }
}tree;
int main()
{
    freopen("in.txt","r",stdin);
    int a,b,c,d;
    while(scanf("%d",&n)!=EOF)
    {
        num=1;
        //int lb=100000,rb=-100000;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            X[num]=a;
            ss[num++]=seg(a,c,b,1);
            X[num]=c;
            ss[num++]=seg(a,c,d,-1);
        }
        sort(ss+1,ss+num);
        sort(X+1,X+num);
        int nx=unique(X+1,X+num)-X-1;
        int ans=0,last=0;
        tree.init();
        for(int i=1;i<num-1;i++)
        {
            int l=lower_bound(X+1,X+nx+1,ss[i].l)-X;
            int r=lower_bound(X+1,X+nx+1,ss[i].r)-X-1;
            tree.update(1,1,nx-1,l,r,ss[i].c);
            ans+=abs(tree.sum[1]-last);
            ans+=tree.numseg[1]*(ss[i+1].h-ss[i].h);
            last=tree.sum[1];
        }
        ans+=tree.sum[1];
        printf("%d\n",ans);
    }
    return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=88010;
struct seg
{
    int l,r,h,c;
    seg(){}
    seg(int a,int d,int b,int t):l(a),r(d),h(b),c(t){}
    bool operator < (const seg &a)const
    {
        if(h==a.h)return c>a.c;
        return h<a.h;
    }
}ss[maxn/4];
int X[maxn];
int n,num;
struct IntevalTree
{
    int cnt[maxn];
    int numseg[maxn];
    int sum[maxn];
    bool lbd[maxn],rbd[maxn];
    //IntevalTree(){}
    void init()
    {
        memset(cnt,0,sizeof(cnt));
        memset(numseg,0,sizeof(numseg));
        memset(sum,0,sizeof(sum));
        memset(lbd,0,sizeof(lbd));
        memset(rbd,0,sizeof(rbd));
    }
    void pushup(int o,int l,int r)
    {
        if(cnt[o])
        {
            lbd[o]=rbd[o]=1;
            sum[o]=X[r]-X[l];
            numseg[o]=2;
        }
        else if(l+1==r)
        {
            lbd[o]=rbd[o]=sum[o]=numseg[o]=0;
        }
        else
        {
            lbd[o]=lbd[o*2];rbd[o]=rbd[o*2+1];
            sum[o]=sum[o*2]+sum[o*2+1];
            numseg[o]=numseg[o*2]+numseg[o*2+1];
            if(lbd[o*2+1]&&rbd[o*2])numseg[o]-=2;
        }
    }
    void update(int o,int l,int r,int q1,int q2,int t)
    {
        if(q1<=l&&r<=q2)
        {
            cnt[o]+=t;
            pushup(o,l,r);
            return;
        }
        int mid=(l+r)/2;
        if(q1<mid)update(o*2,l,mid,q1,q2,t);//注意mid的等号
        if(q2>mid)update(o*2+1,mid,r,q1,q2,t);
        pushup(o,l,r);
    }
}tree;
int main()
{
    freopen("in.txt","r",stdin);
    int a,b,c,d;
    while(scanf("%d",&n)!=EOF)
    {
        num=1;
        //int lb=100000,rb=-100000;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            X[num]=a;
            ss[num++]=seg(a,c,b,1);
            X[num]=c;
            ss[num++]=seg(a,c,d,-1);
        }
        sort(ss+1,ss+num);
        sort(X+1,X+num);
        int nx=unique(X+1,X+num)-X-1;
        int ans=0,last=0;
        tree.init();
        for(int i=1;i<num-1;i++)
        {
            int l=lower_bound(X+1,X+nx+1,ss[i].l)-X;
            int r=lower_bound(X+1,X+nx+1,ss[i].r)-X;
            tree.update(1,1,nx,l,r,ss[i].c);
            ans+=abs(tree.sum[1]-last);
            ans+=tree.numseg[1]*(ss[i+1].h-ss[i].h);
            last=tree.sum[1];
        }
        ans+=tree.sum[1];
        printf("%d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值