--- id: why-cpp title: Why C++? author: Benjamin Qi description: Some reasons why choice of language matters significantly outside of USACO Bronze. --- ## Time Limit Although both Python and Java receive two times the C++ time limit in USACO, this is not the case for most other websites (ex. CodeForces). Even with the extended time limits, Python and Java sometimes have trouble passing. - Rewriting the C++ solution for [USACO Silver Wormsort](http://www.usaco.org/index.php?page=viewproblem2&cpid=992) in Python receives TLE (Time Limit Exceeded) on 2/10 cases. I'm not sure whether it is possible to pass this problem with Python. ```py # 8/10 test cases ... fin = open("wormsort.in","r") lines = [line for line in fin] N,M = map(int,lines[0].split()) p = list(map(lambda x: int(x)-1,lines[1].split())) ed = [] for i in range(2,len(lines)): a,b,w = map(int,lines[i].split()) a -= 1 b -= 1 ed.append([w,a,b]) ed.sort() ed.reverse() adj = [[] for i in range(N)] vis = [0 for i in range(N)] cnt = 0 def dfs(x): global cnt if vis[x] != 0: return vis[x] = cnt for i in adj[x]: dfs(i) def ok(mid): global cnt for i in range(N): vis[i] = 0 adj[i].clear() for i in range(mid): a,b = ed[i][1],ed[i][2] adj[a].append(b) adj[b].append(a) for i in range(N): if vis[i] == 0: cnt += 1 todo = [i] ind = 0 while ind < len(todo): x = todo[ind] ind += 1 vis[x] = cnt for i in adj[x]: if vis[i] == 0: vis[i] = -cnt todo.append(i) ok = True for i in range(N): if vis[i] != vis[p[i]]: ok = False return ok lo,hi = 0,M while lo < hi: mid = (lo+hi)//2 if ok(mid): hi = mid else: lo = mid+1 fout = open("wormsort.out","w") fout.write(str(-1 if lo == 0 else ed[lo-1][0])) fout.write('\n') ``` - A similar solution in Java requires almost 3s, which is fairly close to the time limit of 4s. ```java import java.io.*; // from Nick Wu import java.util.*; public class wormsort { public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new FileReader("wormsort.in")); StringTokenizer st = new StringTokenizer(br.readLine()); int n = Integer.parseInt(st.nextToken()); int m = Integer.parseInt(st.nextToken()); loc = new int[n]; component = new int[n]; edges = new LinkedList[n]; for(int i = 0; i < n; i++) edges[i] = new LinkedList<>(); lhs = new int[m]; rhs = new int[m]; weight = new int[m]; st = new StringTokenizer(br.readLine()); for(int i = 0; i < n; i++) loc[i] = Integer.parseInt(st.nextToken())-1; for(int i = 0; i < m; i++) { st = new StringTokenizer(br.readLine()); lhs[i] = Integer.parseInt(st.nextToken())-1; rhs[i] = Integer.parseInt(st.nextToken())-1; weight[i] = Integer.parseInt(st.nextToken()); } br.close(); int minW = 0; int maxW = 1000000001; while(minW != maxW) { int mid = (minW + maxW + 1) / 2; if(valid(mid)) minW = mid; else maxW = mid-1; } if(minW > 1e9) minW = -1; PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("wormsort.out"))); pw.println(minW); pw.close(); } static int[] loc, lhs, rhs, weight; static LinkedList[] edges; static int[] component; private static void dfs(int curr, int label) { if(component[curr] == label) return; component[curr] = label; for(int child: edges[curr]) dfs(child, label); } private static boolean valid(int minW) { Arrays.fill(component, -1); for(int i = 0; i < edges.length; i++) edges[i].clear(); for(int i = 0; i < lhs.length; i++) { if(weight[i] >= minW) { edges[lhs[i]].add(rhs[i]); edges[rhs[i]].add(lhs[i]); } } int numcomps = 0; for(int i = 0; i < component.length; i++) { if(component[i] < 0) { dfs(i, numcomps++); } } for(int i = 0; i < loc.length; i++) { if(component[i] != component[loc[i]]) return false; } return true; } } ``` - A comparable C++ solution runs in less than 700ms. ```cpp #include using namespace std; typedef vector vi; const int MX = 1e5+5; int loc[MX], comp[MX], lhs[MX], rhs[MX], wei[MX]; vi adj[MX]; int n,m; void dfs(int cur, int label) { if (comp[cur] == label) return; comp[cur] = label; for (int c: adj[cur]) dfs(c,label); } bool valid(int minW) { for (int i = 0; i < n; ++i) { comp[i] = -1; adj[i].clear(); } for (int i = 0; i < m; ++i) if (wei[i] >= minW) adj[lhs[i]].push_back(rhs[i]), adj[rhs[i]].push_back(lhs[i]); int numComps = 0; for (int i = 0; i < n; ++i) if (comp[i] < 0) dfs(i,numComps++); for (int i = 0; i < n; ++i) if (comp[i] != comp[loc[i]]) return 0; return 1; } int main() { ios_base::sync_with_stdio(0); cin.tie(0); freopen("wormsort.in","r",stdin); freopen("wormsort.out","w",stdout); cin >> n >> m; for (int i = 0; i < n; ++i) cin >> loc[i], loc[i] --; for (int i = 0; i < m; ++i) { cin >> lhs[i], lhs[i] --; cin >> rhs[i], rhs[i] --; cin >> wei[i]; } int minW = 0, maxW = (int)1e9+1; while (minW != maxW) { int mid = (minW+maxW+1)/2; if (valid(mid)) minW = mid; else maxW = mid-1; } if (minW > 1e9) minW = -1; cout << minW; } ``` ## Other Notes - USACO problemsetters don't always test Java (and rarely Python) solutions when setting constraints. - Python lacks a data structure that keeps its keys in sorted order (the equivalent of `set` in C++), which is required for some silver problems. - Java lacks features such as `#define`, `typedef`, and `auto` that are present in C++ (which some contestants rely on extensively, see "macros").