持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情
本文已参与「新人创作礼」活动,一 起开启掘金创作之路。
题目
中文大意
给我们n个线段并且给出每个线段的左端点和右端点每个线段都有可能有不同的颜色让我们求出与这个线段不同颜色的线段与它的最近的距离,如果包涵距离为0
解法
解法有很多种 我用的是树状数组加二分
我们可以把每一个线段看成一个区间这样的话就可以把题目变成求区间相交的问题
所以我们假设如果区间中存在一个线段那么我们把加一
我们先将线段按照颜色分类这样我们就可以按照不同的颜色来操作在我们选择一个颜色操作的时候我们把这个颜色的线段从我们的坐标轴上删去这样我们只需要差选这个区间内的数字之和是否大于0即可
但是我们发现数据的范围很大到了1e9所以我们正常的存储时存不下去的所以我们将数据离散化一下
因为我们将线段覆盖转成了区间问题我们使用线段树或树状数组去处理这个问题
因为我写线段树一直RE所以我选择了树状数组的写法
int lowbit(int x) { return x & -x;}
int n,m;
int tr[2][N];
void add(int p, int x) {
for(int i = p; i <= m; i += lowbit(i)) {
tr[0][i] += x, tr[1][i] += x * p;
}
}
void range_add(int l, int r, int x) {
add(l, x), add(r + 1, -x);
}
int ask(int p) {
int res = 0;
for(int i = p; i; i -= lowbit(i)) {
res += (p + 1) * tr[0][i] - tr[1][i];
}
return res;
}
int range_ask(int l, int r) {
return ask(r) - ask(l - 1);
}
这样我们就处理完了区间有重叠的问题现在我们来处理不重复区间的问题我们发现对与一个线段的最左端点离它最近一个肯定是一个在它之前的线段的右端点同理离右端点最近的是左端点这个我们就可以用multiset去维护左端点和右端点因为端点之前可能会有重复的所以我们不能使用set
这样我们所有的情况就处理完了
const int N = 1e6 + 10;
int f[N + N];
int a[N + N];
int lowbit(int x) { return x & -x;}
int n,m;
int tr[2][N];
void add(int p, int x) {
for(int i = p; i <= m; i += lowbit(i)) {
tr[0][i] += x, tr[1][i] += x * p;
}
}
void range_add(int l, int r, int x) {
add(l, x), add(r + 1, -x);
}
int ask(int p) {
int res = 0;
for(int i = p; i; i -= lowbit(i)) {
res += (p + 1) * tr[0][i] - tr[1][i];
}
return res;
}
int range_ask(int l, int r) {
return ask(r) - ask(l - 1);
}
void solve()
{
cin >> n;
vector<int> ans(n + 1,0);
map<int,vector<array<int,3>>> mp;
map<array<int,3>,int> p;
multiset<int> stl,str;
m = 0;
rep(i,n) {
int l,r,c; cin >> l >> r >> c;
mp[c].pb({l,r,i});
a[++m] = l;
a[++m] = r;
stl.insert(l);
str.insert(r);
}
sort(a + 1,a + 1 + m);
m = unique(a + 1, a + m + 1) - a -1;
// rep(i,cnt) cout << a[i] << " \n"[ i == cnt];
auto find = [&](int x) {
return lower_bound(a + 1,a + 1 + m,x) - a;
};
for(auto [idx,a]: mp)
for(auto [l,r,t] : a) add(find(l),1),add(find(r)+1,-1);
for(auto [idx,a]: mp) {
for(auto [l,r,t] : a) {
stl.erase(stl.lower_bound(l));
str.erase(str.lower_bound(r));
add(find(l),-1);
add(find(r) + 1,1);
}
for(auto [l,r,it] : a) {
// cout << range_ask(find(l),find(r)) << endl;
if(range_ask(find(l),find(r)) > 0) {
ans[it] = 0;
continue;
}
int res = 1e9;
auto t = str.lower_bound(l);
if(t != str.begin()) {
t--;
res = l - *t;
}
t = stl.upper_bound(r);
if(t != stl.end()) {
res = min(res,abs(*t - r));
}
ans[it] = res;
}
for(auto [l,r,t] : a) {
stl.insert(l);
str.insert(r);
range_add(find(l),find(r),1);
}
}
rep(i,n) cout << ans[i] << " \n"[ i == n];
for(int i = 1; i <= m; i++)
tr[0][i] = tr[1][i] = 0;
}