首先建议对结点编号的修改使用位运算,因为位运算相较于常规运算要快一些。其次数组大小要开到8倍的n,因为虽然有n条线段,但是有2n个端点。
本题采用权值线段树求解,使用multiset来对左右端点排序和存储,使用set来对左右端点排序和去重,由于左右端点较大,还需要离散化一下再使用线段树。
查询每一种颜色时,需要把相同颜色的线段删掉,防止干扰判断,查完了以后再加回来就ok了
#include<iostream>
#include<set>
#include<map>
#include<vector>
using namespace std;
multiset<int> l, r;
set<int> pos;
const int M = 2e5 + 5;
struct node {
int l, r, posi;
};
typedef long long ll;
vector<node> v[M];
map<int, int> mp;
int tot;
struct T {
int l, r;
ll sum, tag;
}tree[M << 3];
int a[M];
void pushup(int p) {
tree[p].sum = tree[p <<1].sum + tree[p <<1|1].sum;
}
void build(int p, int pl, int pr) {
if (pl == pr) {
tree[p] = { pl,pr,0,0 };
return;
}
tree[p] = { pl,pr,0,0 };
int mid = (pl + pr) >> 1;
build(p<<1, pl, mid);
build(p<<1|1, mid + 1, pr);
pushup(p);
}
void pushdown(int p) {
tree[p <<1].tag += tree[p].tag;
tree[p <<1|1].tag += tree[p].tag;
tree[p<<1].sum += (tree[p <<1].r - tree[p <<1].l + 1LL) * tree[p].tag;
tree[p <<1|1].sum += (tree[p<<1|1].r - tree[p<<1|1].l + 1LL) * tree[p].tag;
tree[p].tag = 0;
}
void update(int p, int L, int R, int x) {
if (L <= tree[p].l && R >= tree[p].r) {
tree[p].sum += (tree[p].r - tree[p].l + 1LL) * x;
tree[p].tag += x;
return;
}
if (tree[p].tag) pushdown(p);
int mid = tree[p].l + tree[p].r >> 1;
if (L <= mid)
update(p<<1, L, R, x);
if (R > mid)
update(p<<1|1, L, R, x);
pushup(p);
}
ll search(int p, int L, int R) {
// cout << "check" << " ";
if (L <= tree[p].l && R >= tree[p].r) {
return tree[p].sum;
}
if (tree[p].tag) pushdown(p);
int mid = (tree[p].l + tree[p].r) >> 1;
ll res = 0;
if (L <= mid)
res += search(p<<1, L, R);
if (R > mid)
res += search(p<<1|1, L, R);
return res;
}
void init(int n) {
tot = 0;
for (int i = 1; i <= n; i++) {
a[i] = 0x3f3f3f3f;
v[i].clear();
v[i].shrink_to_fit();
}
l.clear(); r.clear(); pos.clear(); mp.clear();
}
void sove() {
int n; cin >> n;
init(n);
for (int i = 1; i <= n; i++) {
int L, R, c; cin >> L >> R >> c;
v[c].push_back({ L,R,i });
l.insert(L); r.insert(R);
pos.insert(L); pos.insert(R);
}
// 线段不相交的情况
for (int co = 1; co <= n; co++) {
//先删除相同颜色线段
for (auto it : v[co]) {
int L = it.l; int R = it.r;
l.erase(l.find(L));
r.erase(r.find(R));
}
for (auto it : v[co]) {
int L = it.l; int R = it.r;
auto ml = r.lower_bound(L);
if (ml != r.begin()) //不是最左边的线段
//prev() //默认指向迭代器左边的一个元素
a[it.posi] = min(a[it.posi], L - *prev(ml));
auto mr = l.upper_bound(R);
if (mr != l.end())
a[it.posi] = min(a[it.posi], *mr - R);
}
//重新插入颜色
for (auto it : v[co]) {
int L = it.l; int R = it.r;
l.insert(L); r.insert(R);
}
}
// for (int i = 1; i <= n; i++) cout << a[i] << " ";
// cout << endl;
//线段相交的情况
//离散化
for (auto x : pos) {
mp[x] = ++tot;
}
build(1, 1, tot);
//枚举颜色
for (int co = 1; co <= n; co++) {
for (auto it : v[co]) {
update(1, mp[it.l], mp[it.r], 1);
}
}
for (int co = 1; co <= n; co++) {
//删除颜色
for (auto it : v[co]) {
update(1, mp[it.l], mp[it.r], -1);
}
//查找有没有相交颜色
for (auto it : v[co]) {
int L = mp[it.l]; int R = mp[it.r]; int i = it.posi;
// cout << search(1, L, R) << endl;
if (search(1, L, R) > 0) a[i] = 0;
}
//重新插入颜色
for (auto it : v[co]) {
int L = it.l; int R = it.r;
update(1, mp[L], mp[R], 1);
}
}
for (int p = 1; p <= n; p++) {
cout << a[p] << " ";
}
cout << endl;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) {
sove();
}
}