• [USACO5.5]矩形周长Picture[扫描线+线段树]


    题意:给出一些矩阵,求这些矩阵合并后外部(被包括在内部的不算)周长

    端点-1这个是用点代替了边,区间内有几个点就代表区间长度是多少

    #include <bits/stdc++.h>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    inline void chmax(int &x, int y) {if (x < y) x = y;}
    inline void chmin(int &x, int y) {if (x > y) x = y;}
    int Max = -inf, Min = inf, n, m, tot, ans, lastlen, x, y, xx, yy;
    struct Edge {
    	int l, r, h, v;
    	inline bool operator < (const Edge & rhs) const {
    		return h == rhs.h ? v > rhs.v : h < rhs.h;
    	}
    } G[10005];
    inline void add(int l, int r, int h, int v) {
    	G[++tot] = (Edge) {l, r, h, v};
    }
    struct Node {
    	int sum, cnt, len;
    	//sum区间整体覆盖次数,cnt有几条不相交的线段覆盖了这个区间
    	//len区间内被覆盖的长度
    	bool rcvd, lcvd;//左右端点是否被覆盖
    	Node *ls, *rs;
    	inline void pushup(int l, int r) {
    		if (sum) cnt = 1, len = r-l+1, lcvd = rcvd = 1;
    		else if (l == r) len = 0, cnt = 0, lcvd = rcvd = 0;//Attention
    		else {
    			len = ls->len + rs->len;
    			cnt = ls->cnt + rs->cnt;
    			if (ls->rcvd && rs->lcvd) --cnt;
    			lcvd = ls->lcvd;
    			rcvd = rs->rcvd;
    		}
    	}
    } pool[100005], *root;
    void add(Node *cur, int l, int r, int ql, int qr, int v) {
    	if (ql <= l && r <= qr) return cur->sum += v, cur->pushup(l, r);
    	int mid = l+r>>1;
    	if (ql <= mid) add(cur->ls, l, mid, ql, qr, v);
    	if (qr >  mid) add(cur->rs, mid+1, r, ql, qr, v);
    	cur->pushup(l, r);
    }
    inline Node *newNode() {
    	static int cnt = 0;
    	return &(pool[cnt++]);
    }
    Node *build(int l, int r) {
    	Node *cur = newNode();
    	if (l == r) return cur;
    	int mid = l+r>>1;
    	cur->ls = build(l, mid), cur->rs = build(mid+1, r);
    	return cur;
    }
    
    int main(void) {
    	scanf("%d", &n);
    	for(int i = 1; i <= n; ++i) {
    		scanf("%d%d%d%d", &x, &y, &xx, &yy);
    		chmax(Max, xx), chmin(Min, x), add(x, xx, y, 1), add(x, xx, yy, -1);
    	}
    	if (Min <= 0) {//把坐标转为正数,其实直接加上10001(本题坐标最大值)也是可以的
    		for(int i = 1; i <= tot; ++i) G[i].l += -Min+1, G[i].r += -Min+1;
    		Max -= Min;
    	}
    	root = build(1, Max);
    	sort(G+1, G+1+tot);
    	for(int i = 1; i <= tot; ++i) {
    		add(root, 1, Max, G[i].l, G[i].r-1, G[i].v);//不是很懂为什么要-1,这奇怪的方式
    		while(G[i].h==G[i+1].h&&G[i].v==G[i+1].v) {//防止多次统计答案
    			++i;
    			add(root, 1, Max, G[i].l, G[i].r-1, G[i].v);
    		}
    		ans += abs(root->len-lastlen);//统计横边长度
    		lastlen = root->len;
    		ans += root->cnt*2*(G[i+1].h-G[i].h);//统计竖边长度
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    《Java从入门到放弃》入门篇:springMVC数据校验
    《Java从入门到放弃》入门篇:springMVC数据传递 (二)
    《Java从入门到放弃》入门篇:springMVC数据传递
    《Java从入门到放弃》入门篇:springMVC基本用法
    《Java从入门到放弃》入门篇:spring中AOP的配置方式
    《Java从入门到放弃》入门篇:spring中IOC的注入姿势
    《Java从入门到放弃》入门篇:Struts2的拦截器基本语法
    《Java从入门到放弃》入门篇:Struts2的常用验证方式(二)
    26计算限制的异步操作02-CLR
    26计算限制的异步操作01-CLR
  • 原文地址:https://www.cnblogs.com/storz/p/10191558.html
Copyright © 2020-2023  润新知