扫描线

洛谷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;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值