Ticket to Ride


Problem Statement :


Simon received the board game Ticket to Ride as a birthday present. After playing it with his friends, he decides to come up with a strategy for the game.

There are n cities on the map and n - 1 road plans. Each road plan consists of the following:

Two cities which can be directly connected by a road.
The length of the proposed road.
The entire road plan is designed in such a way that if one builds all the roads, it will be possible to travel between any pair of cities.

A ticket enables you to travel between two different cities. There are m tickets, and each ticket has a cost associated with it. A ticket is considered to be useful if there is a path between those cities.

Simon wants to choose two cities, u and v, and build a minimal number of roads so that they form a simple path between them. Let St  be the sum of costs of all useful tickets and Sr  be the sum of lengths of all the roads Simon builds. The profit for pair ( u, v )  is defined as St - Sr. Note that u and v are not necessarily unique and may be the same cities.

Given n road plans and m ticket prices, help Simon by printing the value of his maximum possible profit on a new line.


Input Format

The first line contains single positive integer, n , denoting the number of cities.
Each of the n - 1  subsequent lines contains three space-separated integers describing the respective values of u , v, and  l for a road plan, where , 1 <= u ,v <= l and u =/ v . Here, u and v are two cities that the road plan proposes to connect and l  is the length of the proposed road.
The next line contains a single positive integer, m, denoting the number of tickets.
Each of the m subsequent lines contains three space-separated integers describing the respective values of u, v, and c for a ticket from city u  to city v (where c is the cost of the ticket).

Constraints

1  <=  n  <=  2 x 10^5
1  <=  m  <=  10^5
1  <=  l , c  <=  10^9


Output Format

Print a single integer denoting the the maximum profit Simon can make.



Solution :



title-img


                            Solution in C :

In   C++  :







#include <bits/stdc++.h>

using namespace std;

#define sz(x) ((int) (x).size())
#define forn(i,n) for (int i = 0; i < int(n); ++i)
#define forab(i,a,b)for(int i =int(a);i<int(b);++i)

typedef long long ll;
typedef long double ld;

const int INF = 1000001000;
const ll INFL = 2000000000000001000;
int solve();


int main()
{
srand(2317);
cout.precision(10);
cout.setf(ios::fixed);
#ifdef LOCAL
assert(freopen("test.in", "r", stdin));
#else
#endif
int tn = 1;
for (int i = 0; i < tn; ++i)
solve();
#ifdef LOCAL
cerr << "Time: " << double(clock()) / 
CLOCKS_PER_SEC << '\n';
#endif
}

const int maxn = 500001;
const int maxm = 100001;
const int maxh = 19;

int ROOT;

int n;
vector<pair<int, int>> g[maxn];
int in[maxn], out[maxn];
int timer = 0;

const int base = 1 << maxh;
ll t[base * 2];
ll upd[base * 2];

ll get()
{
return t[1] + upd[1];
}

int l, r, delta;
inline void put(int v = 1, 
int cl = 0, int cr = base)
{
if (r <= cl || cr <= l)
return;
if (l <= cl && cr <= r)
{
upd[v] += delta;
return;
}
int cc = (cl + cr) >> 1;
put(v << 1, cl, cc);
put((v << 1) + 1, cc, cr);
t[v] = max(t[v << 1] + upd[v << 1], 
t[(v << 1) + 1] + upd[(v << 1) + 1]);
}

inline void add(int v, ll delta)
{
l = in[v], r = out[v], ::delta = delta;
put();
}

vector<pair<int, int>> up[maxn];
vector<pair<int, int>> down[maxn];
vector<pair<int, int>> other[maxn];

inline bool is_prev(int u, int v)
{
return in[u] <= in[v] && out[v] <= out[u];
}

ll best = 0;

void go(int u, int prev = ROOT)
{
for (auto p: other[u])
add(p.first, p.second);
for (auto p: down[u])
{
add(p.first, -p.second);
upd[1] += p.second;
}
for (auto p: up[u])
add(p.first, -p.second);
best = max(best, get());
for (auto p: g[u])
{
if (p.first == prev)
continue;
add(p.first, 2 * p.second);
upd[1] -= p.second;
go(p.first, u);
add(p.first, -2 * p.second);
upd[1] += p.second;
}
for (auto p: other[u])
add(p.first, -p.second);
for (auto p: down[u])
{
add(p.first, p.second);
upd[1] -= p.second;
}
for (auto p: up[u])
add(p.first, p.second);
}

pair<int, int> tickets[maxm];
int ticket_cost[maxm];
int visits[maxm];
int needh[maxm];
int step[maxm];
vector<int> endings[maxn];

int st[maxn], sc = 0;

void dfs(int u, int prev = ROOT, ll depth = 0)
{
st[sc++] = u;
for (int id: endings[u])
{
visits[id]++;
if (visits[id] == 1)
needh[id] = sc;
else if (visits[id] == 2)
step[id] = st[needh[id]];
}
in[u] = timer++;
t[in[u] + base] = -depth;

for (auto p: g[u])
if (p.first != prev)
dfs(p.first, u, depth + p.second);

for (int id: endings[u])
visits[id]--;
out[u] = timer;
--sc;
}

int solve()
{
scanf("%d", &n);
ROOT = rand() % n;
forn (i, n - 1)
{
int u, v, l;
scanf("%d %d %d", &u, &v, &l);
--u, --v;
g[u].emplace_back(v, l);
g[v].emplace_back(u, l);
}
int m;
scanf("%d", &m);
forn (i, m)
{
int u, v, c;
scanf("%d %d %d", &u, &v, &c);
--u, --v;
endings[u].push_back(i);
endings[v].push_back(i);
tickets[i] = {u, v};
ticket_cost[i] = c;
}
fill(step, step + m, -1);
dfs(ROOT);
for (int i = base - 1; i > 0; --i)
t[i] = max(t[i * 2], t[i * 2 + 1]);
forn (i, m)
{
int u = tickets[i].first;
int v = tickets[i].second;
int c = ticket_cost[i];
if (is_prev(v, u))
swap(u, v);
if (is_prev(u, v))
{
assert(step[i] >= 0);
assert(is_prev(u, step[i]));
assert(is_prev(step[i], v));
u = step[i];
add(v, c);
up[u].emplace_back(v, c);
down[v].emplace_back(u, c);
}
else
{
other[u].emplace_back(v, c);
other[v].emplace_back(u, c);
}
}
go(ROOT);
cout << best << '\n';
return 0;
}








In   Python3  :





#!/bin/python3

import os
import sys
from queue import Queue
class Graph:
    def __init__(self, n, roads):
        self.n = n
        self.tree = dict()
        for i in range(n):
            self.tree[i+1] = []
        for i in range(len(roads)):
            self.tree[roads[i][0]].append((roads[i][1], roads[i][2]))
            self.tree[roads[i][1]].append((roads[i][0], roads[i][2]))

    def find_path(self, a, b, visited):
        if visited is None:
            visited = set()
        visited.add(a)
        if a==b:
            return set([a]), 0
        for c, d in self.tree[a]:
            if c not in visited:
                path, p_length = self.find_path(c, b, visited)
                if path is not None:
                    ext_path = path.copy()
                    ext_path.add(a)
                    return ext_path, p_length + d
        return None, 0



# Complete the solve function below.
def solve(roads, tickets):
    max_score = 0
    n = len(roads)+1
    g = Graph(n, roads)
    for a, b, _ in tickets:
        path, cost = g.find_path(a, b, None)
        score = - cost
        for t in tickets:
            if set(t[:2]).issubset(path):
                score += t[2]
        if score > max_score:
            max_score = score
    return max_score
            
if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    n = int(input())

    roads = []

    for _ in range(n-1):
        roads.append(list(map(int, input().rstrip().split())))

    m = int(input())

    tickets = []

    for _ in range(m):
        tickets.append(list(map(int, input().rstrip().split())))

    result = solve(roads, tickets)

    fptr.write(str(result) + '\n')

    fptr.close()
                        








View More Similar Problems

Delete a Node

Delete the node at a given position in a linked list and return a reference to the head node. The head is at position 0. The list may be empty after you delete the node. In that case, return a null value. Example: list=0->1->2->3 position=2 After removing the node at position 2, list'= 0->1->-3. Function Description: Complete the deleteNode function in the editor below. deleteNo

View Solution →

Print in Reverse

Given a pointer to the head of a singly-linked list, print each data value from the reversed list. If the given list is empty, do not print anything. Example head* refers to the linked list with data values 1->2->3->Null Print the following: 3 2 1 Function Description: Complete the reversePrint function in the editor below. reversePrint has the following parameters: Sing

View Solution →

Reverse a linked list

Given the pointer to the head node of a linked list, change the next pointers of the nodes so that their order is reversed. The head pointer given may be null meaning that the initial list is empty. Example: head references the list 1->2->3->Null. Manipulate the next pointers of each node in place and return head, now referencing the head of the list 3->2->1->Null. Function Descriptio

View Solution →

Compare two linked lists

You’re given the pointer to the head nodes of two linked lists. Compare the data in the nodes of the linked lists to check if they are equal. If all data attributes are equal and the lists are the same length, return 1. Otherwise, return 0. Example: list1=1->2->3->Null list2=1->2->3->4->Null The two lists have equal data attributes for the first 3 nodes. list2 is longer, though, so the lis

View Solution →

Merge two sorted linked lists

This challenge is part of a tutorial track by MyCodeSchool Given pointers to the heads of two sorted linked lists, merge them into a single, sorted linked list. Either head pointer may be null meaning that the corresponding list is empty. Example headA refers to 1 -> 3 -> 7 -> NULL headB refers to 1 -> 2 -> NULL The new list is 1 -> 1 -> 2 -> 3 -> 7 -> NULL. Function Description C

View Solution →

Get Node Value

This challenge is part of a tutorial track by MyCodeSchool Given a pointer to the head of a linked list and a specific position, determine the data value at that position. Count backwards from the tail node. The tail is at postion 0, its parent is at 1 and so on. Example head refers to 3 -> 2 -> 1 -> 0 -> NULL positionFromTail = 2 Each of the data values matches its distance from the t

View Solution →