首先建议对结点编号的修改使用位运算,因为位运算相较于常规运算要快一些。其次数组大小要开到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();
	}
}