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,R−1]覆盖的情况,(这里的左右端点是指把输入的所有点排序后,相邻两点左边的点,因而每个点都会成为左端点),由于不必在意端点的具体值,我们对其离散化(二分)处理出相对距离(巨大优化),然后利用差分数组的思想来处理覆盖情况;
// 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