1 条题解

  • 0
    @ 2025-10-19 16:33:01

    https://blog.csdn.net/tenkuo/article/details/153559955?spm=1001.2014.3001.5502

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    #define pl pair<LL, LL>
    #define ppl pair<pl, pl>
    #define x first
    #define y second
    const int N = 3e5 + 10;
    
    vector<pl> ti[N];   // 每个时刻新加进的线段 
    multiset<LL> cont;   // 当前所有缝隙贡献 
    set<ppl> bs;         // 连通块们 
    LL X, Y;            // 起始结束点 
    
    LL calc_dis(LL x, LL y) {   // 计算 floor(sqrt(z)) 
    	LL z = x * x + y * y;
    	LL t = sqrt(z);
    	while (t * t <= z) {
    		t ++;
    	}
    	while (t * t > z) {
    		t --;
    	}
    	return t;
    }
    
    LL part_near(LL l, LL r, LL x) {   // 计算这个区间里离 x 最近的点 
    	if (x < l) {
    		return l;
    	}
    	else if (x > r) {
    		return r;
    	}
    	else {
    		return x;
    	}
    }
    
    void deal_cont(ppl a, ppl b, int flag) {   // 处理两个连通块之间的缝隙 
    	// 计算缝隙范围 
    	pl l = {a.x.y, b.x.x};  // [a.max_x, b.min_x]
    	pl r = {a.y.y, b.y.x};  // [a.max_y, b.min_y]
    	
    	LL dis_x = part_near(l.x, l.y, X); 
    	LL dis_y = part_near(r.x, r.y, Y);
    	LL res = abs(X - dis_x) + abs(Y - dis_y) + calc_dis(dis_x, dis_y);
    	
    	if (flag == 1) {
    		cont.insert(res);   // 添加 
    	}
    	else {
    		// find 返回指针 
    		cont.erase(cont.find(res));    // 删除 
    	}
    } 
    
    // 处理 blo 对应缝隙,flag 为 1 就是加 blo 到平面,为 0 就是删除 
    void change(ppl blo, int flag) {    
    	auto it = bs.find(blo);   // 在 bs 里 找到当前的连通块(返回指针) 
    	if (it != bs.begin()) {   // begin 是存有实体的第一个 
    		deal_cont(*prev(it), *it, flag);
    	} 
    	if (next(it) != bs.end()) {
    		deal_cont(*it, *next(it), flag);
    	}
    	if (it != bs.begin() && next(it) != bs.end()) {   // 找到的左右连通块相邻 
    		deal_cont(*prev(it), *next(it), -flag);
    	}
    } 
    
    bool jd_ab(ppl a, ppl b) {  // 能合并输出 1,不能输出 0 
    	if (a.x.y <= b.x.x && a.y.y <= b.y.x) {
    		return 0;   // a.max_x ≤ b.min_x 且 a.max_y ≤ b.min_y
    	}
    	return 1;
    }
    
    void merge(ppl &a, ppl b) {
    	a.x.x = min(a.x.x, b.x.x);
    	a.x.y = max(a.x.y, b.x.y);
    	a.y.x = min(a.y.x, b.y.x);
    	a.y.y = max(a.y.y, b.y.y);
    } 
    
    void ins(pl line) {    // 将这条线段加到平面里 
    	ppl blo = { {line.x, line.x}, {line.y, line.y} };
    	// 当只有一条线段时的连通块:x 下界与上界,y 下界与上界 
    	
    	while(1) {   // 不断地合并 
    		auto it = bs.lower_bound(blo);   // 当前连通块右边的连通块 
    		if (it != bs.end() && jd_ab(blo, *it)) {   // 不是边界且可以合并 
    			change(*it, -1);    // 把原来这个连通块缝隙贡献减掉 
    			merge(blo, *it);    // 合并 
    			bs.erase(it);       // 合并了就删掉 
    			continue;
    		}
    		// begin 是存有实体的第一个
    		if (it != bs.begin() && jd_ab(*prev(it), blo)) {   // 不是边界且可以合并 
    			auto _it = prev(it);      // prev 不是持久迭代器,后续还要删除,先开一个指针存着 
    			change(*_it, -1);    // 把原来这个连通块缝隙贡献减掉
    			merge(blo, *_it);    // 合并 
    			bs.erase(_it);       // 合并了就删掉 
    			continue;
    		}
    		break;    // 没得合并了退出 
    	} 
    	
    	bs.insert(blo);   // 并完了就放进去 
    	change(blo, 1);  // 把缝隙加进去 
    } 
    
    int main () {
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	
    	int n, T;
    	cin >> n >> T;
    	cin >> X >> Y;
    	
    	for (int i = 1; i <= n; i ++) {
    		int t; LL x, y;
    		cin >> t >> x >> y;
    		ti[t].push_back({x, y});
    	}
    	
    	ins({0, 0});    // 上下边界(保证有缝隙) 
    	ins({1e9, 1e9});   // 不然会卡似 
    	
    	for (int i = 0; i < T; i ++) {     // 题目时间范围 
    		for (auto j : ti[i]) {
    			ins(j);
    		}
    		cout << (*cont.begin()) << "\n";   // 路程最小的那个 
    	}
    	
    	return 0;
    }
    
    • 1

    信息

    ID
    6923
    时间
    2000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    15
    已通过
    4
    上传者