您的位置:首页 > 其它

HDU Atlantis 线段树 表达区间 矩形面积相交

2016-11-16 00:10 169 查看
http://acm.hdu.edu.cn/showproblem.php?pid=1542

我的做法是把x轴的表示为线段,然后更新y

#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;
}


View Code

求解区间

[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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: