当前位置: 首页 > article >正文

并集运算的线段树维护方式

题目

给定 n n n 个区间 [ l , r ] [l,r] [l,r],满足 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1lrn,求它们的并集的长度。

线段树做法

设计一个线段树维护以下操作:

  1. 区间修改。
  2. 单点查询。

其中线段树单点 i i i 代表的区间为 [ l , r ) [l,r) [l,r) ,对于每个单点使用 set 或 map 维护。

如果值域过大,使用离散化。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
#include <ctime>
#include <random>
#include <set>
#include <map>
#include <bitset>
#define int long long
using namespace std;

const int INF = 0x3f3f3f3f;

inline int read()
{
	int w = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		w = (w << 1) + (w << 3) + (ch ^ 48);
		ch = getchar();
	}
	return w * f;
}

inline void write(int x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
const int maxn = 8e5 + 5;
int sl[maxn], sr[maxn], nl[maxn], nr[maxn], val[maxn * 2];
int cntn;

struct node
{
	int l, r;
	int val, tag;
} tr[maxn * 4];
void print(node x)
{
	cout << x.l << " " << x.r << " " << x.val << " " << x.tag << endl;
}

int ls(int p)
{
	return p << 1;
}
int rs(int p)
{
	return p << 1 | 1;
}
void pushdown(int p)
{
	int tag = tr[p].tag;
	if (tr[p].tag != -1)
	{
		tr[ls(p)].val = tag;
		tr[rs(p)].val = tag;
		tr[ls(p)].tag = tag;
		tr[rs(p)].tag = tag;
		tr[p].tag = -1;
	}
}
void build(int p, int l, int r)
{
	tr[p].l = l, tr[p].r = r;
	if (l == r)
	{
		tr[p].tag = -1;
		return;
	}
	int mid = l + r >> 1;
	build(ls(p), l, mid);
	build(rs(p), mid + 1, r);
}
void update(int p, int l, int r, int x)
{

	if (l <= tr[p].l && tr[p].r <= r)
	{
		tr[p].val = x;
		tr[p].tag = x;
		return;
	}
	pushdown(p);
	int mid = (tr[p].l + tr[p].r) / 2;
	if (mid >= l) update(ls(p), l, r, x);
	if (mid < r) update(rs(p), l, r, x);
}
int query(int p, int x)
{
	if (tr[p].l == x && tr[p].r == x)
	{
		return tr[p].val;
	}
	pushdown(p);
	int mid = (tr[p].l + tr[p].r) / 2;
	if (mid >= x) return query(ls(p), x);
	else  return query(rs(p), x);
}
using namespace std;
int n, m;
struct sss
{
	int l, r;
} t[200005];
map<int, int> d;
vector<int> ans;
int mp[maxn * 2];
signed main()
{
	n = read();
	for (int i = 1; i <= n; ++i)
	{
		t[i].l = sl[i] = read(), t[i].r = sr[i] = read();
		++cntn;
		val[cntn] = mp[cntn] = sl[i];
		++cntn;
		val[cntn] = mp[cntn] = sr[i];
	}
	sort(val + 1, val + cntn + 1);
	cntn = unique(val + 1, val + cntn + 1) - val - 1;
	for (int i = 1; i <= n; ++i)
	{
		nl[i] = lower_bound(val + 1, val + cntn + 1, sl[i]) - val;
		nr[i] = lower_bound(val + 1, val + cntn + 1, sr[i]) - val;
	}
	for (int i = 1; i <= cntn; ++i)
	{
		mp[i] = lower_bound(val + 1, val + cntn + 1, val[i]) - val;
	}
	build(1, 1, cntn);
	map<int, int> dpoint;
	for (int i = 1; i <= n; ++i)
	{
		if (nl[i] == nr[i])
		{
			dpoint[nl[i]] = 1;
			continue;
		}
		if (nl[i] != nr[i])
		{
			update(1, nl[i], nr[i] - 1, 1);
			dpoint[nr[i]] = 1;
			if (dpoint.find(nl[i]) != dpoint.end())
			{
				dpoint.erase(dpoint.find(nl[i]));
			}
		}
	}
	for (int i = 1; i < cntn; ++i)
	{
		if (query(1, i) == 1)
		{
			if (dpoint.find(i) != dpoint.end())
			{
				dpoint.erase(dpoint.find(i));
			}
			ans.push_back(i);
		}
	}
	if (ans.empty() && dpoint.empty())
	{
		puts("0");
		return 0;
	}
	else if (ans.empty())
	{
		cout << dpoint.size() << endl;
		return 0;
	}
	int tot = 0;
	for (int i = 0; i < ans.size(); ++i)
	{
		tot += val[ans[i] + 1 ] - val[ans[i]];
	}
	cout << tot + dpoint.size() << endl;
	return 0;
}

拓展

问:如何求出具体区间?

答: 根据最后一步显然。


http://www.kler.cn/news/330858.html

相关文章:

  • c++就业磁盘链式b树与b+树
  • 3. 将GitHub上的开源项目导入(clone)到本地pycharm上——深度学习·科研实践·从0到1
  • 滚雪球学MySQL[7.1讲]:安全管理
  • 【笔记】数据结构12
  • Dubbo和Http的调用有什么区别
  • 【Docker】docker的存储
  • el-table动态表头
  • 828华为云征文|部署音乐流媒体服务器 mStream
  • React返回上一个页面,会重新挂载吗
  • 【AI知识点】非独立同分布(non-iid, non-independent and identically distributed)
  • AR技术在电商行业的应用及优势有哪些?
  • 解决银河麒麟V10系统bash执行提示:无法执行:权限不够的问题
  • 远程过程调用RPC知识科普
  • 【Linux】进程管理:状态与优先级调度的深度分析
  • 车辆种类分类识别数据集,可以识别7种汽车类型,已经按照7:2:1比 例划分数据集,训练集1488张、验证集507张,测试集31张, 共计2026张。
  • 【Spring Security】基于SpringBoot3.3.4版本整合JWT的使用教程
  • HBase批量写入优化
  • 安宝特分享 | AR技术重塑工业:数字孪生与沉浸式培训的创新应用
  • Android SystemUI组件(08)睡眠灭屏 锁屏处理流程
  • 用Sklearn和Statsmodels来做linear_regression和Logistic_regression注意事项