zoukankan      html  css  js  c++  java
  • 我的线段树扫描线问题模板

    /*
    在求周长之前最好线看一下求面积,这样再求周长回好理解很多。
    题目是POJ 1177 http://poj.org/problem?id=1177
    POJ 1151也是这类问题,不过是求面积的,更简单一些。
    */ #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <ctime> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; const int N = 10010; struct xLine { int x; //存放横坐标,对纵坐标表示的进行线段树上的染色操作 int y1; // int y2; //x,y1,y2表示四边型的一条竖边,x是纵坐标,y1,y2表示上下界 bool f; //f = true表示这条边是这个四边型的左边那条边(入边),f = false表示出边 bool operator < (const xLine l) const { //重载 <,按x从小到大排序 return x < l.x; } }Line[N]; struct xnode { int l, r; //线段树的左右边界 int len; //线段树所表示的当前线段的长度 int sum; //被覆盖的长度 int lsum; //被覆盖过的区间数,这个在累加横边长度的时候用到,看下边的代码画画图就ok了 int cover; //当前线段被覆盖的次数 bool lcover; //标记当前线段左端点是否被覆盖 bool rcover; //标记当前线段右端点是否被覆盖 xnode() { l = r = 0; len = sum = cover = lsum = 0; lcover = rcover = false; } }node[N<<2]; int ind[N]; int n, m; void build(int t, int l, int r) { //建树 node[t].l = l; node[t].r = r; node[t].len = ind[r] - ind[l]; node[t].sum = node[t].lsum = node[t].cover = 0; node[t].lcover = node[t].rcover = false; if(r - l > 1) { //要建成单位为1的线段形式 int mid = MID(l, r); build(L(t), l, mid); build(R(t), mid, r); } } void Up_sum(int t) { //更新区间内被覆盖的长度 if(node[t].cover > 0) node[t].sum = node[t].len; else if(node[t].r - node[t].l > 1) node[t].sum = node[L(t)].sum + node[R(t)].sum; else node[t].sum = 0; } void Up_lsum(int t) { //更新区间被没覆盖的线段长度 if(node[t].cover > 0) { node[t].lcover = node[t].rcover = true; node[t].lsum = 1; } else if(node[t].r - node[t].l > 1) { node[t].lcover = node[L(t)].lcover; node[t].rcover = node[R(t)].rcover; node[t].lsum = node[L(t)].lsum + node[R(t)].lsum - node[L(t)].rcover*node[R(t)].lcover; } else { node[t].lcover = node[t].rcover = false; node[t].lsum = 0; } } void updata(int t, int l, int r, bool c) { //更新线段树,c = 1表示插入线段,c = 0表示删除线段 if(node[t].l == l && node[t].r == r) { if(c) node[t].cover++; else node[t].cover--; Up_sum(t); Up_lsum(t); return ; } int mid = MID(node[t].l, node[t].r); if(r <= mid) updata(L(t), l, r, c); else if(l >= mid) updata(R(t), l, r, c); else { updata(L(t), l, mid, c); updata(R(t), mid, r, c); } Up_sum(t); Up_lsum(t); } inline int iabs(int x) { return x < 0 ? -x : x; } int find(int x) { //给y轴上的点重新编号,传说中的离散化 int l = 0, r = m, mid; while(l <= r) { mid = MID(l, r); if(ind[mid] == x) return mid; else if(ind[mid] > x) r = mid - 1; else l = mid + 1; } return 0; } int main() { //freopen("data.in", "r", stdin); int i, x1, y1, x2, y2; while(~scanf("%d", &n)) { CL(Line, 0); CL(node, 0); REP(i, n) { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); Line[i*2].x = x1; Line[i*2].y1 = y1; Line[i*2].y2 = y2; Line[i*2].f = 1; //入边 Line[i*2+1].x = x2; Line[i*2+1].y1 = y1; Line[i*2+1].y2 = y2; Line[i*2+1].f = 0; //出边 ind[i*2] = y1; ind[i*2+1] = y2; //这里用来记录y轴上所有的坐标,用来离散话 } sort(ind, ind + n*2); sort(Line, Line + n*2); m = 1; for(i = 0; i < n*2 - 1; ++i) { //删掉多余的点 if(ind[i] != ind[i+1]) ind[m++] = ind[i+1]; } /*for(i = 0; i < m; ++i) printf("%d ", ind[i]); cout << endl;*/ build(1, 0, m-1); //建树 int ans = 0; int presum = 0; for(i = 0; i < 2*n - 1; ++i) { if(Line[i].f) updata(1, find(Line[i].y1), find(Line[i].y2), 1); //入边则insert else updata(1, find(Line[i].y1), find(Line[i].y2), 0); //出边则delete ans += node[1].lsum*(Line[i+1].x - Line[i].x)*2; //这个累加平行与x轴的边 ans += iabs(node[1].sum - presum); //累加平行与y轴的边,画画图就可以看清楚了 presum = node[1].sum; } updata(1, find(Line[2*n-1].y1), find(Line[2*n-1].y2), 0); //别忘了最后一个出边要删除 ans += iabs(node[1].sum - presum); printf("%d\n", ans); } return 0; }
  • 相关阅读:
    oracle 添加用户
    oracle---存储结构及其之间的关系和创建数据库
    oracle---临时表空间
    对字符串进行加密解密知识
    面向对象---函数重复---原型
    Ajax
    sqlHelper+app.config
    sqlHelper ---转载
    web.config中的连接字符串 ---关于 providerName 特性---转载
    SQL中的cast()函数--转载
  • 原文地址:https://www.cnblogs.com/vongang/p/2560816.html
Copyright © 2011-2022 走看看