QOJ9431 The Quest for El Dorado 做题记录
QOJ9431 The Quest for El Dorado
Description
给一张 \(n\) 个点,\(m\) 条边的无向图,每条边有长度 \(w\) 和颜色 \(c\)。从节点 \(1\) 开始一共要走 \(k\) 轮,每一轮可以一次性走完颜色均为 \(a_i\) 且长度之和不超过 \(b_i\) 的边或原地不动。问 \(k\) 轮走完以后能走到哪些点。
\(1\leq n,m,k\leq 5\times 10^5\)。
Solution
被唐题创飞了。
首先注意到这个问题与最短路模型非常像,所以我们考虑如何设计 “距离”。
我们到达一个点时,首先希望已经经过的轮数尽量小,其次希望在这一轮中走过的距离尽量小,这样有利于后续的扩展。所以我们以 “轮数 \(r\)” 为第一关键字,“本轮走过的距离 \(d\)” 为第二关键字排序。
考虑 Dijkstra 算法。当我们从 \(x\) 扩展到 \(y\) 时,分两种情况讨论:
- \((x,y)\) 这条边的颜色与本轮颜色相同,且 \(w(x,y)+d\leq b\)。此时我们直接用 \((r,d+w)\) 尝试扩展;
- 否则,我们需要找到 \(a_i=c\)、在 \(r\) 之后、\(b_i\geq w\) 且最靠前的一轮 \(i\),用 \((i,w)\) 尝试扩展。
第二种情况我们可以对每种颜色的轮分别维护一个区间最大值 st 表,查询时二分即可。
时间复杂度 \(O((n+m)\log m+m\log k)\)。
启示:最短路模型;设计距离,考虑扩展。
int n,m,k;
int lg[N];
struct Ticket{
int c,d;
}a[N];
struct TicketSet{
vector<int> s;
vector<vector<int> > f;
int cnt;
void Clear(){
s.clear();
f.clear();
cnt=0;
}
int Ask(int l,int r){
int x=lg[r-l+1];
return max(f[l][x],f[r-(1<<x)+1][x]);
}
void Init(){
cnt=s.size();
f.resize(cnt+2);
for(int i=0;i<cnt;i++){
f[i].resize(lg[cnt]+2);
f[i][0]=a[s[i]].d;
}
for(int j=1;j<=lg[cnt];j++){
for(int i=0;i+(1<<j)-1<cnt;i++)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
int Find(int x,int d){
int p=lower_bound(s.begin(),s.end(),x)-s.begin();
int l=p,r=cnt-1,res=-1;
while(l<=r){
int mid=(l+r)>>1;
if(Ask(p,mid)>=d) res=mid,r=mid-1;
else l=mid+1;
}
if(res==-1) return -1;
else return s[res];
}
}T[N];
int head[N],tot;
struct Edge{
int to,nxt,col,val;
}edge[N<<1];
void Add(int u,int v,int c,int w){
edge[++tot]={v,head[u],c,w};
head[u]=tot;
}
void Clear(){
for(int i=1;i<=m;i++) T[i].Clear();
for(int i=1;i<=n;i++) head[i]=0;
tot=0;
}
pii dis[N];
bool vis[N];
struct Node{
int x,r,d;
bool operator<(const Node& tmp)const{
return r>tmp.r||(r==tmp.r&&d>tmp.d);
}
};
void Dijkstra(){
for(int i=1;i<=n;i++){
vis[i]=0;
dis[i]={IINF,IINF};
}
dis[1]={1,0};
priority_queue<Node> q;
q.push({1,1,0});
while(q.size()){
int x=q.top().x; q.pop();
if(vis[x]) continue;
vis[x]=1;
int r=dis[x].first,d=dis[x].second;
for(int i=head[x];i;i=edge[i].nxt){
int t=edge[i].to;
if(vis[t]) continue;
int c=edge[i].col,w=edge[i].val;
if(a[r].c==c&&d+w<=a[r].d){
if(dis[t]>pii{r,d+w}){
dis[t]={r,d+w};
q.push({t,r,d+w});
}
}
else{
int p=T[c].Find(r+1,w);
if(p==-1) continue;
if(dis[t]>pii{p,w}){
dis[t]=pii{p,w};
q.push({t,p,w});
}
}
}
}
}
void Solve(){
read(n),read(m),read(k);
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
Clear();
for(int i=1;i<=m;i++){
int u,v,c,w;
read(u),read(v),read(c),read(w);
Add(u,v,c,w);
Add(v,u,c,w);
}
for(int i=1;i<=k;i++){
read(a[i].c),read(a[i].d);
T[a[i].c].s.push_back(i);
}
for(int i=1;i<=m;i++) T[i].Init();
Dijkstra();
for(int i=1;i<=n;i++){
if(dis[i].first<=k) putchar('1');
else putchar('0');
}
puts("");
}
signed main(){
int _; read(_);
while(_--) Solve();
return 0;
}

浙公网安备 33010602011771号