2024昆明邀请赛J. The Quest for El Dorado (ST表+Dijkstra)

Problem - J - Codeforces

 

 

题目大意:给你n个点,m条无向边,每条边由Ai管理,边长为Bi,再给你K次操作,要顺序执行,可以选择跳过该操作或执行该操作,起点从1开始,要求从u->v这条路径属于当前这个操作的Ai, 并且边长累计(连续走的路径都由Ai管理且仍是第i个操作)不超过Bi,否则选择第i个操作之后第一个管理者是A,且边长大于等于B的操作执行。最后输出所有能走到的位置。

思路:思路很好想,用小顶堆存{第i张票序号、这张票已经走过的路程,顶点} ,每次遍历当前这个点的邻接点,如果与上一次的管理者相同则看这张票的剩余路程是否大于这条边的长度,否则就要查找[i+1,k]这个区间中第一个管理者为A,且长度大于等于B的票,可以通过对每个管理者的车票路程长度 B 建ST表,二分查找解决。

Code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <limits.h>
#include <set>
#include <array>
#define int long long

using namespace std;
using aii =array<int,3>;

typedef pair<int,int> PII;
typedef pair<char,int> PCI;
typedef pair<string,aii> PSII;
#define fi first
#define se second
const int N=1e6+5;

int n,m,k;
int e[N],ne[N],c[N],w[N],idx,h[N];
int ans[N];

struct STList{
  vector<vector<int>> stmax;
    void init(vector<int>& a)
    {
        int len=a.size();
        int K=__lg(len)+1;
        stmax.assign(len,vector<int>(K));
        for(int i=0;i<len;i++)
            stmax[i][0]=a[i];
        
        for(int j=1;j<K;j++)
        {
            for(int i=0;i+(1<<(j))-1<len;i++)
            {
                stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<(j-1))][j-1]);
            }
        }
    }
    
    int query(int l,int r)
    {
        int j=__lg(r-l+1);
        return max(stmax[l][j],stmax[r-(1<<j)+1][j]);
    }
};
void add(vector<int> &h,int a,int b,int c1,int d)
{
  e[idx]=b,ne[idx]=h[a],w[idx]=d,c[idx]=c1,h[a]=idx++;
}

void solve()
{
   cin>>n>>m>>k;
   vector<int> h(2*m+5,-1);
 //  vector<int> ans(n+1,0);
  // vector<bool> st(n+1,false);
      idx=0;
     vector<bool> st(n+1,false);
   for(int i=1;i<=m;i++)
   {
     int a,b,c1,d;cin>>a>>b>>c1>>d;
     add(h,a,b,c1,d),add(h,b,a,c1,d);
   }
   vector<vector<int> > q(m+1);
vector<vector<int>> q1(m+1);
    vector<int> t(k+1),dis(k+1);
    vector<STList> f(m+1);
    t[0]=0;
   for(int i=1;i<=k;i++)
   {
      int a,b;cin>>a>>b;
       t[i]=a;
       dis[i]=b;
      q[a].push_back(b);
      q1[a].push_back(i);
   }
   for(int i=1;i<=m;i++)
   {
       if(q[i].size())
           f[i].init(q[i]);
   }
   priority_queue<aii,vector<aii>,greater<aii> > p;
   
   p.push({0,0,1});
   while(p.size())
   {
     auto [id,l,u]=p.top();p.pop();
     if(st[u]) continue;
     st[u]=1;
     //  cout<<"---"<<endl;
     for(int i=h[u];~i;i=ne[i])
     {
         
      int j=e[i];//cout<<j<<endl;
      if(c[i]==t[id])
      {
        if(dis[id]-l>=w[i])
        {
          p.push({id,l+w[i],j});
        }
        else
        {

          auto pp=upper_bound(q1[t[id]].begin(),q1[t[id]].end(),id);
          if(pp!=q1[t[id]].end()){
          int j1=pp-q1[t[id]].begin();
              int r1=q1[t[id]].size()-1;
           int L=j1,R=r1;
          //    cout<<"--- "<<f[t[id]].query(L,R)<<endl;
           if(f[t[id]].query(L,R)<w[i]) continue;
              while(L<R)
              {
                  int mid=(L+R)>>1;
                  if(f[t[id]].query(j1,mid)>=w[i]) R=mid;
                  else L=mid+1;
              }
            p.push({q1[t[id]][R],w[i],j});
        }
        }
      }
      else
      {
        auto pp=upper_bound(q1[c[i]].begin(),q1[c[i]].end(),id);
          if(pp!=q1[c[i]].end()){
           int j1=pp-q1[c[i]].begin();
              int r1=q1[c[i]].size()-1;
           int L=j1,R=r1;
            //  cout<<"--- "<<f[c[i]].query(L,R)<<endl;
           if(f[c[i]].query(L,R)<w[i]) continue;
              while(L<R)
              {
                  int mid=(L+R)>>1;
                  if(f[c[i]].query(j1,mid)>=w[i]) R=mid;
                  else L=mid+1;
              }
             p.push({q1[c[i]][R],w[i],j});
        }
        
      }
     }
   }
   for(int i=1;i<=n;i++)
    cout<<(st[i]?1:0);
  cout<<endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int t;cin>>t;
 //   memset(h,-1,sizeof h);
    //t=1;
    while(t--) solve();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SuperRandi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值