http://acm.hdu.edu.cn/showproblem.php?pid=1542
我的做法是把x轴的表示为线段,然后更新y
不考虑什么优化的话,开始的时候,把他们表达成线段,并按y排序,然后第一次加入线段树的应该就是最底下那条,然后第二条的时候,我们可以询问第二条那段区间,有多少是已经被覆盖的,然后把面积算上就可以。
所以如果区间都是整数,而且数值很少,那么就是线段树成段覆盖的问题了。但是这里是浮点数而且很大。
所以只能把它离散化。
这个时候线段树就不是连续的了,这里就有bug,问题就变成了怎么表达这颗线段树了。
思路是把它弄成L + 1 == R就是叶子节点,这样的话,每个节点都保存了一个区间了,
例如
要保存5、10、15、30
一般的线段树
5、30
5、10 15、30
5 10 15 30
但是这样怎么表示[10, 15]这段区间呢?
所以把线段树变成
5、30
5、10 10、 30
10、15 15、30
就行了。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> int n; const int maxn = 2e2 + 20; struct node { int L, R; double x1, x2, y; int cover; } seg[maxn << 2]; struct info { double x1, x2, y; int flag; bool operator < (const struct info & rhs) const { return y < rhs.y; } } in[maxn]; double xx[maxn]; void build(int L, int R, int cur) { seg[cur].cover = 0; seg[cur].x1 = xx[L]; seg[cur].x2 = xx[R]; seg[cur].y = -1; seg[cur].L = L; seg[cur].R = R; if (L + 1 == R) { //两个节点作为一个叶子 return; } int mid = (L + R) >> 1; build(L, mid, cur << 1); build(mid, R, cur << 1 | 1); } double upDate(int begin, int end, double y, int flag, int cur) { if (end <= seg[cur].L || begin >= seg[cur].R) return 0; if (seg[cur].L + 1 == seg[cur].R) { if (seg[cur].cover) { double ans = (seg[cur].x2 - seg[cur].x1) * (y - seg[cur].y); seg[cur].cover += flag; seg[cur].y = y; return ans; } else { seg[cur].cover += flag; seg[cur].y = y; return 0; } } double ans = upDate(begin, end, y, flag, cur << 1) + upDate(begin, end, y, flag, cur << 1 | 1); return ans; } void work() { int lenin = 0; int lenxx = 0; for (int i = 1; i <= n; ++i) { double xx1, xx2, yy1, yy2; scanf("%lf%lf%lf%lf", &xx1, &yy1, &xx2, &yy2); lenin++; in[lenin].x1 = xx1; in[lenin].x2 = xx2; in[lenin].y = yy1; in[lenin].flag = 1; lenxx++; xx[lenxx] = xx1; lenin++; in[lenin].x1 = xx1; in[lenin].x2 = xx2; in[lenin].y = yy2; in[lenin].flag = -1; lenxx++; xx[lenxx] = xx2; } sort(in + 1, in + 1 + lenin); sort(xx + 1, xx + 1 + lenxx); lenxx = unique(xx + 1, xx + 1 + lenxx) - (xx + 1); build(1, lenxx, 1); double ans = 0; const int root = 1; for (int i = 1; i <= lenxx; ++i) { printf("%f** ", xx[i]); } for (int i = 1; i <= lenin; ++i) { int L = lower_bound(xx + 1, xx + 1 + lenxx, in[i].x1) - xx; int R = lower_bound(xx + 1, xx + 1 + lenxx, in[i].x2) - xx; // cout << L << " " << R << endl; ans += upDate(L, R, in[i].y, in[i].flag, root); } static int f = 0; printf("Test case #%d ", ++f); printf("Total explored area: %0.2f ", ans); // printf("%0.2f ", ans); } int main() { #ifdef local freopen("data.txt","r",stdin); #endif while (scanf("%d", &n) != EOF && n) { work(); printf(" "); } return 0; }
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; const int maxn = 1e3 + 20; struct Node { double x1, x2, y; int L, R; int cover; }seg[maxn << 2]; vector<double> vc; int n; struct Info { double x1, x2, y; int cover; bool operator < (const struct Info & rhs) const { return y < rhs.y; } }fuck[maxn * 2]; void build(int L, int R, int cur) { seg[cur].L = L, seg[cur].R = R; seg[cur].x1 = vc[L], seg[cur].x2 = vc[R]; seg[cur].y = -inf; seg[cur].cover = 0; if (L + 1 == R) return; int mid = (L + R) >> 1; build(L, mid, cur << 1); build(mid, R, cur << 1 | 1); } double add(int x1, int x2, double y, int cover, int cur) { if (x2 <= seg[cur].L || x1 >= seg[cur].R) return 0; if (seg[cur].L + 1 == seg[cur].R) { if (seg[cur].cover) { double res = (y - seg[cur].y) * (seg[cur].x2 - seg[cur].x1); seg[cur].cover += cover; seg[cur].y = y; // 更新最大值y return res; } else { seg[cur].cover += cover; seg[cur].y = y; return 0; } } return add(x1, x2, y, cover, cur << 1) + add(x1, x2, y, cover, cur << 1 | 1); } void work() { vc.clear(); vc.push_back(-1.0); int len = 0; for (int i = 1; i <= n; ++i) { double x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2; ++len; fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = 1; ++len; fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1; vc.push_back(x1); vc.push_back(x2); } sort(vc.begin(), vc.end()); sort(fuck + 1, fuck + 1 + len); build(1, vc.size(), 1); double ans = 0; for (int i = 1; i <= len; ++i) { int x1 = lower_bound(vc.begin(), vc.end(), fuck[i].x1) - vc.begin(); int x2 = lower_bound(vc.begin(), vc.end(), fuck[i].x2) - vc.begin(); ans += add(x1, x2, fuck[i].y, fuck[i].cover, 1); } static int f = 0; printf("Test case #%d ", ++f); printf("Total explored area: %.2f ", ans); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif while (cin >> n && n) work(); return 0; }
跪着看这篇blog想的
http://www.cnblogs.com/ka200812/archive/2011/11/13/2247064.html
2017年8月15日 13:35:12
http://acm.hdu.edu.cn/showproblem.php?pid=1255
只需要cover >= 2才计算
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; const int maxn = 1e3 + 20; struct Node { double x1, x2, y; int L, R; int cover; }seg[maxn << 2]; vector<double> vc; int n; struct Info { double x1, x2, y; int cover; bool operator < (const struct Info & rhs) const { return y < rhs.y; } }fuck[maxn * 2]; void build(int L, int R, int cur) { seg[cur].L = L, seg[cur].R = R; seg[cur].x1 = vc[L], seg[cur].x2 = vc[R]; seg[cur].y = -inf; seg[cur].cover = 0; if (L + 1 == R) return; int mid = (L + R) >> 1; build(L, mid, cur << 1); build(mid, R, cur << 1 | 1); } double add(int x1, int x2, double y, int cover, int cur) { if (x2 <= seg[cur].L || x1 >= seg[cur].R) return 0; if (seg[cur].L + 1 == seg[cur].R) { if (seg[cur].cover >= 2) { double res = (y - seg[cur].y) * (seg[cur].x2 - seg[cur].x1); seg[cur].cover += cover; seg[cur].y = y; // 更新最大值y return res; } else { seg[cur].cover += cover; seg[cur].y = y; return 0; } } return add(x1, x2, y, cover, cur << 1) + add(x1, x2, y, cover, cur << 1 | 1); } void work() { vc.clear(); vc.push_back(-1.0); int len = 0; scanf("%d", &n); for (int i = 1; i <= n; ++i) { double x1, y1, x2, y2; scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); ++len; fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = 1; ++len; fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1; vc.push_back(x1); vc.push_back(x2); } sort(vc.begin(), vc.end()); sort(fuck + 1, fuck + 1 + len); build(1, vc.size(), 1); double ans = 0; for (int i = 1; i <= len; ++i) { int x1 = lower_bound(vc.begin(), vc.end(), fuck[i].x1) - vc.begin(); int x2 = lower_bound(vc.begin(), vc.end(), fuck[i].x2) - vc.begin(); ans += add(x1, x2, fuck[i].y, fuck[i].cover, 1); } printf("%.2f ", ans); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif int t; scanf("%d", &t); while (t--) work(); return 0; }
http://codeforces.com/contest/610/problem/D
这题要用到另一种方法
不然TLE
这题是把线条表达成一个长度大小是1的矩形
如果矩形表达成[x1, x2],那么边长应该是x2 - x1 + 1(因为在直线的意义下所有点都覆盖了)
所以要把矩形表达成[x1 - 1, x2],同时要注意统一化,就是水平的和垂直的都是按照这个方向改。
x轴要固定向左端减小。
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; const int maxn = 400000 + 20; struct Info { int x1, x2, cover; LL y; bool operator < (const struct Info & rhs) const { return y < rhs.y; } } fuck[maxn]; vector<int> vc; struct Node { int L, R; int x1, x2, y; int cover; }seg[maxn << 2]; void build(int L, int R, int cur) { seg[cur].L = L, seg[cur].R = R; seg[cur].x1 = vc[L], seg[cur].x2 = vc[R]; seg[cur].y = 0; seg[cur].cover = 0; if (L + 1 == R) return; int mid = (L + R) >> 1; build(L, mid, cur << 1); build(mid, R, cur << 1 | 1); } void pushUp(int cur) { if (seg[cur].cover) { seg[cur].y = vc[seg[cur].R] - vc[seg[cur].L]; } else if (seg[cur].L + 1 == seg[cur].R) { seg[cur].y = 0; } else { seg[cur].y = seg[cur << 1].y + seg[cur << 1 | 1].y; } } void add(int be, int en, int y, int cover, int cur) { if (seg[cur].L > en || seg[cur].R < be) return; if (seg[cur].L >= be && seg[cur].R <= en) { seg[cur].cover += cover; pushUp(cur); return; } add(be, en, y, cover, cur << 1); add(be, en, y, cover, cur << 1 | 1); pushUp(cur); } void work() { vc.clear(); vc.push_back(-inf); int n, len = 0; scanf("%d", &n); for (int i = 1; i <= n; ++i) { int x1, y1, x2, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2); if (x1 == x2) { if (y1 > y2) swap(y1, y2); ++len; fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1 - 1, fuck[len].cover = 1; ++len; fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1; vc.push_back(x1 - 1); vc.push_back(x2); } else { if (x1 > x2) swap(x1, x2); ++len; fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = -1; ++len; fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1 - 1, fuck[len].cover = 1; vc.push_back(x1 - 1); vc.push_back(x2); } } sort(vc.begin(), vc.end()); // vc.erase(unique(vc.begin(), vc.end()), vc.begin()); sort(fuck + 1, fuck + 1 + len); build(1, vc.size(), 1); LL ans = 0; for (int i = 1; i < len; ++i) { int x1 = lower_bound(vc.begin(), vc.end(), fuck[i].x1) - vc.begin(); int x2 = lower_bound(vc.begin(), vc.end(), fuck[i].x2) - vc.begin(); add(x1, x2, fuck[i].y, fuck[i].cover, 1); ans += seg[1].y * (fuck[i + 1].y - fuck[i].y); } cout << ans << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
求解区间
[L1, R1]、[L2, R2].....这样区间的,线段树的叶子节点一定要维护两个值。才算是叶子节点。就是上面所说的
主要是:因为这些区间不是连续的。
例如
要保存5、10、15、30
一般的线段树
5、30
5、10 15、30
5 10 15 30
是无法得到a[4] - a[1] = 25的区间长度的。
如果你直接跑线段树,就是左右儿子的总和加上来。这样就是10 - 5 + 30 - 15 = 20
漏了一段,那一段?10--15
所以表示成
5 10 15 30
5 10 10 15 30
10 15 15 30
是一种好的选择,因为这和一般的线段树不同,一般的线段树都是连续的整数,现在是分散的。所以要这样来代表
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #define lson L, mid, cur << 1 #define rson mid, R, cur << 1 | 1 #define root 1, all, 1 const int maxn = 600000 + 20; struct Info { int x1, x2, cover; LL y; bool operator < (const struct Info & rhs) const { return y < rhs.y; } } fuck[maxn]; vector<int> vc; LL seg[maxn << 2], cov[maxn << 2]; void pushUp(int cur, int L, int R) { if (cov[cur]) seg[cur] = vc[R] - vc[L]; else if (L + 1 == R) seg[cur] = 0; else { seg[cur] = seg[cur << 1] + seg[cur << 1 | 1]; } } void upDate(int be, int en, int val, int L, int R, int cur) { if (L > en || R < be) return; if (L >= be && R <= en) { cov[cur] += val; pushUp(cur, L, R); return; } if (L + 1 == R) return; //必须的 int mid = (L + R) >> 1; upDate(be, en, val, lson); upDate(be, en, val, rson); //维护两个节点 pushUp(cur, L, R); } void work() { vc.clear(); vc.push_back(-inf); int n, len = 0; scanf("%d", &n); for (int i = 1; i <= n; ++i) { int x1, y1, x2, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2); if (x1 == x2) { if (y1 > y2) swap(y1, y2); ++len; fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1 - 1, fuck[len].cover = 1; ++len; fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1; vc.push_back(x1 - 1); vc.push_back(x2); } else { if (x1 > x2) swap(x1, x2); ++len; fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = -1; ++len; fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1 - 1, fuck[len].cover = 1; vc.push_back(x1 - 1); vc.push_back(x2); } } // for (int i = 1; i <= n; ++i) { // int x1, y1, x2, y2; // cin >> x1 >> y1 >> x2 >> y2; // vc.push_back(x1); // vc.push_back(x2); // ++len; // fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = 1; // ++len; // fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1; // } //上面注释只是普通的矩形面积交。 sort(vc.begin(), vc.end()); sort(fuck + 1, fuck + 1 + len); int all = vc.size() - 1; //只能去到-1 LL ans = 0; for (int i = 1; i < len; ++i) { int x1 = lower_bound(vc.begin(), vc.end(), fuck[i].x1) - vc.begin(); int x2 = lower_bound(vc.begin(), vc.end(), fuck[i].x2) - vc.begin(); upDate(x1, x2, fuck[i].cover, root); // cout << seg[1] << endl; ans += seg[1] * (fuck[i + 1].y - fuck[i].y); } cout << ans << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; } 矩形面积交数据 2 1 0 3 3 2 1 4 4