ICPC2024昆明邀请赛 J The Quest for El Dorado 题解

Question

The Quest for El Dorado

某个国家有 \(n\) 座城市以及 \(m\) 条连接城市的双向铁路。第 \(i\) 条铁路由第 \(c_i\) 家铁路公司运营,铁路的长度是 \(l_i\)。您想要从城市 1 开始进行全国旅行。您已经为旅行购买了 k 张车票。第 \(i\) 张车票可以记为两个整数 \(a_i\)\(b_i\),表示如果您使用了这张车票,就可以一次性经过若干条均由公司 \(a_i\) 运营的,且总长度不超过 \(b_i\)的铁路。即使您使用了车票,也可以选择待在当前城市。您同时只能使用一张车票,且每张车票只能使用一次。由于决定车票的使用顺序太麻烦了,您打算直接按现有的顺序使用车票。更正式地,您将执行 k 次操作。在第 \(i\) 次操作中,您可以选择待在当前的城市 u;也可以选择一座不同的城市 v,满足城市 uv之间存在一条路径,且路径上的所有铁路均由公司 \(a_i\) 运营,且铁路总长不超过 \(b_i\),然后移动到城市 v

对于每座城市,判断在使用 k 张车票之后能否到达该城市。

Solution

从第一个点出发,遍历每一条边,用类似于 \(dijkstra\) 的方法,按照票的时间为第一关键字, 距离为第二关键字作为最短路的距离,对于同一张票,转移需要考虑票的距离是否能大于等于到当前点的距离加上边的距离,而对于不同的票,只需要考虑第一个大于等于该点时间和距离的票(类似于二维偏序问题),考虑ST表加二分。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 5e5 + 5;
const ll INF = 1e14;
struct node{
    ll col, u, v, w;
};
struct ds{
    ll id, time, dist;
};
bool operator < (ds xx, ds yy){
    if(xx.time == yy.time) return xx.dist > yy.dist;
    return xx.time > yy.time;
}
struct ST{
	vector<vector<ll>> f;
    ll len;
	void init(vector<pair<ll, ll>> &a){
        f.resize(len + 5, vector<ll>(22, 0));
		for(int i = 1; i <= len; i ++){
			f[i][0] = a[i].second;
		}
		for(int j = 1; j <= 20; j ++){
			for(int i = 1; i + (1 << j) - 1 <= len; i ++){
				f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
			}
		}
	}
	ll query(ll l, ll r){
		ll k = log2(r - l + 1);
		return max(f[l][k], f[r - (1 << k) + 1][k]);
	}
}xm[MAXN];
ll Tex, n, m, k;
bool flag[MAXN];
ll tis[MAXN];
ll dis[MAXN];
vector<node> mp[MAXN];
vector<pair<ll, ll>> cp[MAXN];
void dijkstra(){
    priority_queue<ds> op;
    op.push({1, 0, 0});
    tis[1] = 0;
    dis[1] = 0;
    while(!op.empty()){
        ds qwq = op.top();
        op.pop();
        if(flag[qwq.id]) continue;
        flag[qwq.id] = 1;
        for(auto it : mp[qwq.id]){
            if(flag[it.v]) continue;
            ll idx = lower_bound(cp[it.col].begin(), cp[it.col].end(), make_pair(qwq.time, 0ll)) - cp[it.col].begin();
            if(idx == cp[it.col].size()) continue;
            if(cp[it.col][idx].first == qwq.time){
                if(cp[it.col][idx].second >= qwq.dist + it.w){
                    tis[it.v] = qwq.time;
                    dis[it.v] = qwq.dist + it.w;
                    op.push({it.v, tis[it.v], dis[it.v]});
                    continue;
                }
                idx ++;
            }
            ll l = idx, r = cp[it.col].size();
            while(l < r){
                ll mid = l + r >> 1;
                if(xm[it.col].query(l, mid) >= it.w) r = mid;
                else l = mid + 1;
            }
            if(cp[it.col].size() <= l) continue;
            if(tis[it.v] < cp[it.col][l].first) continue;
            if(xm[it.col].query(l, l) >= it.w){
                tis[it.v] = cp[it.col][l].first;
                dis[it.v] = it.w;
                op.push({it.v, tis[it.v], dis[it.v]});
            }
        }
    }
    for(int i = 1; i <= n; i ++){
        if(flag[i]) cout << 1;
        else cout << 0;
    }
    cout << endl;
    return;
}
void AC(){
    cin >> n >> m >> k;
    for(int i = 1; i <= n; i ++){
        mp[i].clear();
        flag[i] = 0;
        tis[i] = INF;
        dis[i] = INF;
    }
    for(int i = 1; i <= m; i ++){
        cp[i].clear();
        cp[i].push_back({-1, -1});
        ll x, y, col, z;
        cin >> x >> y >> col >> z;
        mp[x].push_back({col, x, y, z});
        mp[y].push_back({col, y, x, z});
    }
    for(int i = 1; i <= k; i ++){
        ll col, dist;
        cin >> col >> dist;
        cp[col].push_back({i, dist});
    }
    for(int i = 1; i <= m; i ++){
        if(cp[i].size() > 1){
            xm[i].len = cp[i].size() - 1;
            xm[i].init(cp[i]);
        }
    }
    dijkstra();
}
int main(){
    ios::sync_with_stdio(false);
    cin >> Tex;
    while(Tex --) AC();
    return 0;
}
posted @ 2024-05-31 16:14  XiaoMo247  阅读(936)  评论(0)    收藏  举报