CF F. Multi-Colored Segments

代码如下

不知道是有什么恶心的数据还是怎么样,一直过不了40个点,始终超时

搞懂了tree要开M<<3,因为虽然有2e5条线段,但是左右节点有4e5个,所以要开8倍的n


//出错原因1: build树的时候,左右区间没给结点赋值完,只赋值了pl==pr的部分

//出错原因2:update中要查找的区间和现在遍历到的区间混淆了

#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 * 2].sum + tree[p * 2 + 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 * 2, pl, mid);
	build(p * 2 + 1, mid + 1, pr);
	pushup(p);
}

void pushdown(int p) {
	tree[p * 2].tag += tree[p].tag;
	tree[p * 2 + 1].tag += tree[p].tag;
	tree[p * 2].sum += (tree[p * 2].r - tree[p * 2].l + 1LL) * tree[p].tag;
	tree[p * 2 + 1].sum += (tree[p * 2 + 1].r - tree[p * 2 + 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 * 2, L, R, x);
	if (R > mid)
		update(p * 2 + 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 * 2, L, R);
	if (R > mid)
		res += search(p * 2 + 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 << '\n';
}

int main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	int t; cin >> t;
	while (t--) {
		sove();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值