1 条题解

  • 0
    @ 2025-5-12 21:06:49

    首先我们现在改一下线段树保存的属性,我们用如下信息记录线段树的节点:

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

    2.len : 这个区间被覆盖的长度(即计算时的有效长度)

    3.s : 表示这个区间被覆盖了几次

    1. lc , rc : 标记这个节点的左右两个端点是否被覆盖(0表示没有,1表示有)

    5.num :这个区间有多少条不连续线段(这个区间被多少条线段覆盖)

    这里的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(两区间连起来还是一段)

    然后就可以计算竖线了:

    竖线的长度 = 【下一条即将被扫到的横线的高度 - 现在扫到的横线的高度】2num

    乘2是因为每条线段有两个端点;

    看上图中棕色线段的竖线有4条,因为棕色的横线由2条线段组成

    白色线段的竖线只有2条,因为白色的横线由1条线段组成(虽然这1条线段是由许多线段组合而成,但它依旧只算1条线段)

    这样,依旧只扫一次就可以算出周长。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define ls i<<1
    #define rs i<<1|1
    #define m(i) ((q[i].l+q[i].r)>>1)
    typedef long long ll;
    const int N = 5007;
    const int X = 20007;
    const int inf = 1<<29;
    struct Edge{
    	int l,r;
    	int h;
    	int f;
    	bool operator < (const Edge &a)const{
    		return h < a.h;
    	}
    }e[N*2];
    struct Node{
    	int l,r;
    	int len;
    	int s;
    	bool lc,rc;//表示这个节点代表的区间左右两个端点是否被覆盖
    	int num;//这个区间有多少不连续到线段
    }q[X*4];
    void pushup(int i){
    	if(q[i].s){
    		q[i].len = q[i].r - q[i].l + 1;
    		q[i].lc = q[i].rc = 1;
    		q[i].num = 1;
    	}
    	else if(q[i].l == q[i].r){
    		q[i].len = 0;
    		q[i].lc = q[i].rc = 0;
    		q[i].num = 0;
    	}
    	else{
    		q[i].len = q[ls].len + q[rs].len;
    		q[i].lc = q[ls].lc;
    		q[i].rc = q[rs].rc;
    		q[i].num = q[ls].num + q[rs].num - (q[ls].rc & q[rs].lc);
    	}
    }
    void build(int i,int l,int r){
    	q[i].l = l;
    	q[i].r = r;
    	q[i].s = q[i].len = 0;
    	q[i].lc = q[i].rc = q[i].num = 0;
    	if(l == r) return;
    	int mid = m(i);
    	build(ls,l,mid);
    	build(rs,mid+1,r);
    }
    void update(int i,int l,int r,int xx){
    	if(l == q[i].l && q[i].r == r){
    		q[i].s += xx;
    		pushup(i);
    		return;
    	}
    	int mid = m(i);
    	if(r <= mid) update(ls,l,r,xx);
    	else if(l > mid) update(rs,l,r,xx);
    	else{
    		update(ls,l,mid,xx);
    		update(rs,mid+1,r,xx);
    	}
    	pushup(i);
    }
    int main(){
    	int n;
    	while(scanf("%d",&n) != EOF){
    		int x1,x2,y1,y2,mx = -inf,mn = inf;
    		int tot = 0;
    		for(int i = 0; i < n; i++){
    			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    			mx = max(mx,max(x1,x2));
    			mn = min(mn,min(x1,x2));
    			Edge &t1 = e[tot];
    			Edge &t2 = e[tot+1];
    			t1.l = t2.l = x1;
    			t1.r = t2.r = x2;
    			t1.h = y1;
    			t1.f = 1;
    			t2.h = y2;
    			t2.f = -1;
    			tot += 2;
    		}
    		sort(e,e+tot);
    		//数据小不用离散化
    		int ans = 0;
    		int last = 0;
    		build(1,mn,mx-1);
    		for(int i = 0; i < tot; i++){
    			update(1,e[i].l,e[i].r-1,e[i].f);
    			ans += abs(q[1].len - last);
    			ans += (e[i+1].h - e[i].h) * 2 * q[1].num;
    			last = q[1].len;
    		}
    		printf("%d\n",ans);
    	}
    	return 0;
    }
    • 1

    信息

    ID
    178
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者