C. Covered Points Count

本文介绍了如何使用二分和差分数组优化算法解决 Educational Codeforces Round 46 中的线段覆盖计数问题。通过离散化处理和差分数组技巧,解决了在给定n条线段情况下计算被覆盖点数的高效方法。
摘要由CSDN通过智能技术生成

Educational Codeforces Round 46 (Rated for Div. 2)
date:2021/11/16

题目大意:

给出n条线段,输出多少个点被1到n条线段覆盖;

思路:

暴力思考,对每个区间 [ l . r ] [l.r] [l.r]+1,最后 O ( M A X r ) O(MAX r) O(MAXr) 统计一下每个点被覆盖的情况,显然是会TLE的;
观察发现相邻两个端点之间的点被同样多的线段覆盖(不包含右端点),那么我们可以用 c n t cnt cnt 数组
记录左端点 L 被多少个线段覆盖用以表示区间 [ L , R − 1 ] [L,R-1] [L,R1]覆盖的情况,(这里的左右端点是指把输入的所有点排序后,相邻两点左边的点,因而每个点都会成为左端点),由于不必在意端点的具体值,我们对其离散化(二分)处理出相对距离(巨大优化),然后利用差分数组的思想来处理覆盖情况;

// Problem: C. Covered Points Count
// Contest: Codeforces - Educational Codeforces Round 46 (Rated for Div. 2)
// URL: https://codeforces.com/problemset/problem/1000/C
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define _orz ios::sync_with_stdio(false),cin.tie(0)
#define mem(str,num) memset(str,num,sizeof(str))
#define forr(i,a,b) for(ll i = a;i <= b;i++)
#define forn(i,n) for(int i = 0; i < n; i++)
#define all(a) a.begin(),a.end()
#define dbg() cout << "0k!" << endl;
//#define _DEBUG
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 2e5+10;
const ll MOD = 1e9+7;


void so1ve(){
	int n; cin >> n;
	vector<pair<ll,ll>>a(n);
	vector<ll> cval;
	
	for(auto &i:a){
		cin >> i.first >> i.second;
		cval.push_back(i.first);
		cval.push_back(i.second+1);
	}
	sort(all(cval));// 排序;
	cval.erase(unique(all(cval)),cval.end()); // 对重复端点去重,后面用于二分;
	
	vector<int> cnt(2*n); // n 个线段覆盖会生成 2*n个线段 ,(一个点也是一个线段;
	for(auto &i:a){
		int pos1 = lower_bound(all(cval),i.first) - cval.begin();
		int pos2 = lower_bound(all(cval),i.second+1) - cval.begin();
		++cnt[pos1];//差分数组 区间修改
		--cnt[pos2];//差分数组 区间修改
	}
	vector<ll> ans(n+1);
	for(int i = 1; i < 2*n;i++)	cnt[i] += cnt[i-1]; // 对差分数组求前缀和 得到cnt[i] 即覆盖后第i条覆盖后生成的线段的覆盖情况;
	for(int i = 1; i < 2*n;i++){
		ans[cnt[i-1]] += cval[i] - cval[i-1]; 
	}
	
	forr(i,1,n) cout << ans[i] <<" \n"[i==n];
	
	//vector<vector<int>> p(n,vector<int>(m));
}	
int main()
{
#ifdef _DEBUG
    //freopen("input.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
	_orz;
    int t= 1;
    while(t--) so1ve();
    return 0;
}

如有错误,还望指出
ORZ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值