Submission #241456

#TimeUsernameProblemLanguageResultExecution timeMemory
241456kal013Olympic Bus (JOI20_ho_t4)C++17
100 / 100
713 ms5776 KiB
/*/ Author: kal013 /*/
// #pragma GCC optimize ("O3")
#include "bits/stdc++.h"
#include "ext/pb_ds/assoc_container.hpp"
#include "ext/pb_ds/tree_policy.hpp"
using namespace std;
using namespace __gnu_pbds;

template<class T> 
using ordered_set = tree<T, null_type,less<T>, rb_tree_tag,tree_order_statistics_node_update> ;

template<class key, class value, class cmp = std::less<key>>
using ordered_map = tree<key, value, cmp, rb_tree_tag, tree_order_statistics_node_update>;
// find_by_order(k)  returns iterator to kth element starting from 0;
// order_of_key(k) returns count of elements strictly smaller than k;

template<class T>
using min_heap = priority_queue<T, vector<T> , greater<T> >;

struct custom_hash { // Credits: https://codeforces.com/blog/entry/62393
    static uint64_t splitmix64(uint64_t x) {
        // http://xorshift.di.unimi.it/splitmix64.c
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};

template<class T> ostream& operator<<(ostream &os, vector<T> V) {
    os << "[ ";
    for(auto v : V) os << v << " ";
    return os << "]";
}
template<class T> ostream& operator<<(ostream &os, set<T> S){
    os << "{ ";
    for(auto s:S) os<<s<<" ";
    return os<<"}";
}
template<class T> ostream& operator<<(ostream &os, unordered_set<T> S){
    os << "{ ";
    for(auto s:S) os<<s<<" ";
    return os<<"}";
}
template<class T> ostream& operator<<(ostream &os, ordered_set<T> S){
    os << "{ ";
    for(auto s:S) os<<s<<" ";
    return os<<"}";
}
template<class L, class R> ostream& operator<<(ostream &os, pair<L,R> P) {
    return os << "(" << P.first << "," << P.second << ")";
}
template<class L, class R> ostream& operator<<(ostream &os, map<L,R> M) {
    os << "{ ";
    for(auto m:M) os<<"("<<m.first<<":"<<m.second<<") ";
    return os<<"}";
}
template<class L, class R> ostream& operator<<(ostream &os, unordered_map<L,R> M) {
    os << "{ ";
    for(auto m:M) os<<"("<<m.first<<":"<<m.second<<") ";
    return os<<"}";
}
template<class L, class R, class chash = std::hash<R> > ostream& operator<<(ostream &os, gp_hash_table<L,R,chash> M) {
    os << "{ ";
    for(auto m:M) os<<"("<<m.first<<":"<<m.second<<") ";
    return os<<"}";
}

#define TRACE
#ifdef TRACE
    #define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
    template <typename Arg1>
    void __f(const char* name, Arg1&& arg1){
        cerr << name << " : " << arg1 << endl;
    }
    template <typename Arg1, typename... Args>
    void __f(const char* names, Arg1&& arg1, Args&&... args){
        const char* comma = strchr(names + 1, ',');
        cerr.write(names, comma - names) << " : " << arg1<<" | ";
        __f(comma+1, args...);
    }
#else
    #define trace(...) 1
#endif

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

inline int64_t random_long(long long l,long long r){
    uniform_int_distribution<int64_t> generator(l,r);
    return generator(rng);
}
inline int64_t random_long(){
    uniform_int_distribution<int64_t> generator(LLONG_MIN,LLONG_MAX);
    return generator(rng);
}


/*/---------------------------Defines----------------------/*/
typedef vector<int> vi;
typedef pair<int,int> pii;

#define ll long long
#define F first
#define S second
#define pb push_back
#define endl "\n"
#define all(v) (v).begin(),(v).end()
/*/-----------------------Modular Arithmetic---------------/*/

const int mod=1e9+7;
inline int add(int x,int y){
    x+=y;
    if (x>=mod) return x-mod;
    return x;
}
inline int sub(int x,int y){
    x-=y;
    if (x<0) return x+mod;
    return x;
}
inline int mul(int x,int y){
    return (x*1ll*y)%mod;
}
inline int power(int x,int y){
    int ans=1;
    while(y){
        if (y&1) ans=mul(ans,x);
        x=mul(x,x);
        y>>=1;
    }
    return ans;
}
inline int inv(int x){
    return power(x,mod-2);
}
/*/-----------------------------Code begins----------------------------------/*/
const int N = 210;
const int M = 5e4+100;
vector<int> adj[N][2];

vector<int> g[N];
const ll INF = 1e15+2;

ll dis[N][N];

int U[M][2]; 
ll C[M],D[M];




ll dp[2][N][N][2];

ll compress[2][2][M];


ll dist[N];
int par[N];

bitset<M> vis;


void init_dijkstra(int src,int n,int idx,int ignore_edge, bool do_par,bool prev_init = false){
	// assert(src == 1 || src == n);
	// assert(idx == 0 || idx == 1);
	// assert(n < N && ignore_edge < M);
	min_heap<pair<ll,ll> > queue;

	if (!prev_init){
		for(int i = 1; i <= n; ++i){
			dist[i] = INF;
			if (do_par) par[i] = -1;
		}
		dist[src] = 0;


		queue.push({0,src});
	}
	else{
		vector<int> ex,rem;
		for(int i = 1;  i<=n; ++i){
			if (dist[i] < INF){
				ex.push_back(i);
			}
			else{
				rem.push_back(i);
			}
		}

		for(auto X: ex){
			for(auto i : adj[X][idx]){
				if (i == ignore_edge) continue;
				int v = U[i][0]^U[i][1]^X;
				dist[v] = min(dist[v],dist[X] + C[i]);
			}
		}



		for(auto vv: rem){
			if (dist[vv] < INF) queue.push({dist[vv],vv});
		}
	}
	

	while(!queue.empty()){
		auto X = queue.top();
		queue.pop();
		if (X.first > dist[X.second]) continue;
		if (X.first >= INF) break;
		// assert(dist[X.second] == X.first);


		for(auto i: adj[X.second][idx]){
			if (i == ignore_edge) continue;
			int v = U[i][0]^U[i][1]^X.second;
			
			// assert( 1 <= v && v <= n);

			if (dist[v] > dist[X.second] + C[i]){
				dist[v] = dist[X.second] + C[i];

				queue.push({dist[v],v});
				if (do_par) par[v] = i;
			}

		}
	}


}

void do_dp(int idx,int src,int n,int m){
	// assert( idx == 0 || idx == 1);
	// assert(src == 1 || src == n);
	int s_id = (src == 1) ? 0 : 1;

	init_dijkstra(src,n,idx,m + 10,true);

	for(int i = 0; i<= m; ++i){
		vis[i] = false;
	}
	vector<int> used;

	for(int i = 1; i<=n; ++i){
		g[i].clear();
	}

	for(int zz = 1; zz <= n ; ++zz){
		auto e = par[zz];
		if (e != -1) {
			// assert(zz != src);
			// assert(0 <= e && e < m); 
			int v = U[e][0] ^ U[e][1] ^ zz;
			g[v].push_back(zz);

			used.push_back(e); 
			vis[e] = true;
		}
	}
	// assert(used.size() < n);
	for(int i = 0; i<m ;++i){
		if (!vis[i]){
			compress[idx][s_id][i] = 0;
			
		}
	}

	for(int z = 1; z <= n; ++z){
		dp[idx][z][0][s_id] = dist[z];
	}


	int cntr = 1;
	for(auto e: used){

		int u = U[e][idx], v = U[e][idx^1];
		assert(par[v] == e);

		for(int i = 1; i <= n; ++i){
			dist[i] = dp[idx][i][0][s_id];
		}

		vector<int> bfs = {v};

		for(int i = 0; i < bfs.size() ; ++i){
			int cur = bfs[i];
			dist[cur] = INF;	
			for(auto edge : g[cur]){
				bfs.push_back(edge);
			}
		}

		bfs.clear();

		init_dijkstra(src,n,idx,e,false,true);
		
		compress[idx][s_id][e] = cntr;


		for(int z = 1; z <= n; ++z){
			dp[idx][z][cntr][s_id] = dist[z];
		}

		++cntr;

	}





}


inline ll get_dp_val(ll idx,ll n,ll m, ll s_id){
	ll cntr = compress[idx][s_id][m];

	return dp[idx][n][cntr][s_id];
}

void solve(){
    int n,m;
    cin>>n>>m;
    // assert( n < N && m < M);
    for(int i = 1; i<=n ; ++i){
    	for(int j = 1; j<=n ; ++j){
    		dis[i][j] = INF;
    	}
    	dis[i][i] = 0;
    }

    for(int i = 0; i < m; ++i){
    	cin>>U[i][0]>>U[i][1]>>C[i]>>D[i];
    	ll u = U[i][0], v = U[i][1];

    	// assert(1 <= u && u <= n && 1 <= v && v <= n);
    	dis[u][v] = min(dis[u][v], C[i]);

    	adj[u][0].push_back(i);
    	adj[v][1].push_back(i);
    }

    for(int mid = 1; mid <= n; ++mid){
    	for(int src = 1; src <= n; ++src){
    		for(int des = 1; des <= n ; ++des){
    			dis[src][des] = min(dis[src][mid] + dis[mid][des],dis[src][des]);
    		}
    	}
    }

    ll ans = min(INF, dis[1][n] + dis[n][1]);
    do_dp(0,1,n,m);
    do_dp(0,n,n,m);
    do_dp(1,1,n,m);
    do_dp(1,n,n,m);


    for(int i = 0; i < m; ++i){
    	ll u = U[i][0], v = U[i][1];

    	ll cur_s_t = get_dp_val(0,n,i,0);
    	cur_s_t = min(cur_s_t, get_dp_val(0,v,i,0) + get_dp_val(1,u,i,1) + C[i]);


    	ll cur_t_s = get_dp_val(0,1,i,1);

    	cur_t_s = min(cur_t_s, get_dp_val(0,v,i,1) + get_dp_val(1,u,i,0) + C[i]);

    	ans = min(ans, cur_t_s + cur_s_t + D[i]);
    }
    if (ans >= INF){
    	ans = -1;
    }
    cout<<ans<<endl;
}
int main(){
    // Use "set_name".max_load_factor(0.25);"set_name".reserve(512); with unordered set
    // Or use gp_hash_table<X,null_type>
    ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
    cout<<fixed<<setprecision(25);
    cerr<<fixed<<setprecision(10);
    auto start = std::chrono::high_resolution_clock::now();
    int t=1;
    // cin>>t;
    while(t--) {
        solve();
    }
    auto stop = std::chrono::high_resolution_clock::now(); 
    auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start); 
    
    // cerr << "Time taken : " << ((long double)duration.count())/((long double) 1e9) <<"s "<< endl;     
}




Compilation message (stderr)

ho_t4.cpp: In function 'void do_dp(int, int, int, int)':
ho_t4.cpp:291:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   for(int i = 0; i < bfs.size() ; ++i){
                  ~~^~~~~~~~~~~~
ho_t4.cpp:282:7: warning: unused variable 'u' [-Wunused-variable]
   int u = U[e][idx], v = U[e][idx^1];
       ^
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...