洛谷5490
与普通线段树不同点:
如果正常的线段树区间是1~5 子节点:1~3 4~5
但是这里就会少算3~4区间里的东西
所以是1~3 3~5
然后叶子结点的l、r : l+1 == r
添加链接描述
具体看代码 差不多都有解释
不懂的地方可以@一下
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 2e5 + 7;
int mark[N<<4];//记录某个区间的下底边个数
long long sum[N<<4];//记录某个区间下底边总长度
vector<int> v;//对x进行离散化
//以横轴坐标作为线段(区间)
//对横坐标线段进行扫描
//扫描的作用是每次更新下底边总长度和下底边个数
//增加新面积
struct Node{
int l, r, h, d;
Node(){}
Node(int x1, int x2, int t, int c):l(x1), r(x2),h(t),d(c){}
bool operator< (const Node &a) const {
return h < a.h;
}
}arr[N<<2];
void Upfather(int k, int l, int r)
{
if (mark[k]) sum[k] = v[r-1] - v[l-1];
//表示该区间整个线段长度可作为底边
else if (l == r) sum[k] = 0;
//叶子节点则底边长度为0(区间线段长度位0)
else sum[k] = sum[k<<1] + sum[k<<1|1];
}
void update(int x, int y, int num, int k, int l, int r)
{
// printf ("%d\n", k);
if (x <= l && y >= r)
{
// printf ("%d\n", k);
// printf ("%d %d\n", l , r);
mark[k] += num; //更新底边相差个数
Upfather(k, l, r);// 更新底边长
return ;
}
int mid = l + r >> 1;
if (x < mid) update(x, y, num, k << 1, l, mid);
if (y > mid) update(x ,y, num, k << 1 | 1, mid, r);
Upfather(k, l, r);
}
int search(int key)
{
return lower_bound(v.begin(), v.end(), key) - v.begin() + 1;
}
int main ()
{
int n, len = 0;
int x1, x2, y1, y2;
int k = 0;
scanf ("%d", &n);
memset(sum, 0, sizeof sum);
memset(mark, 0, sizeof mark);
for (int i = 0 ; i < n; i ++ )
{
scanf ("%d%d%d%d", &x1, &y1, &x2, &y2);
arr[k++] = Node(x1, x2, y1, 1);
arr[k++] = Node(x1, x2, y2, -1);
v.push_back(x1);
v.push_back(x2);
}
sort(v.begin(), v.end());
sort(arr, arr + k);
// int m = 1;
// for (int i = 0; i < k; i ++ ) printf ("%d ", hash[i]);
v.erase(unique(v.begin(), v.end()), v.end());
// printf ("%d\n", m);
long long ans = 0;
for (int i = 0; i < k - 1; i ++ ){
int l= search(arr[i].l);
int r= search(arr[i].r);
update(l, r, arr[i].d, 1, 1, v.size());
//扫描线段时更新底边长度和底边相差个数
ans += 1ll*sum[1]*(arr[i + 1].h - arr[i].h);//新增面积
}
printf ("%lld\n", ans);
return 0;
}