We use cookies to ensure you have the best browsing experience on our website. Please read our cookie policy for more information about how we use cookies.
// Hackerrank 2022-06-27 task (GO) Super Maximum Cost Queries.txt// https://www.hackerrank.com/challenges/maximum-cost-queries/problem/*Where Cost of a path is the MAX edge weight along path,Report count of paths in [L..R] inclusive weight range.Another Disjoint Set Union problem.Idea: progressively grow a DSU from smallest to largest weight,and sum the various (n * n-1 / 2) paths in all the DSU subsets.// Suppose I don't re-sum all DS, but only the two// affected: union len(m) with len(n) => len(m+n).So, on the sample data:5 51 2 31 4 22 5 63 4 11 11 22 32 51 6Resort {u, v, w} by ascending weights w:3 4 11 4 21 2 32 5 6after adding w=1: 3-4, there is one DS of 2 nodes, whose edge weight==max weight== 1.after adding w=2: 1-4, there is one DS of 3 nodes. 3 * 2 / 2 = 3 paths, of max == 2.after adding w=3: 1-2, there is one DS of 4 nodes. 4 * 3 / 2 = 6 paths, of max == 3.after adding w=6: 2-6, there is one DS of 5 nodes. 5 * 4 / 2 = 10 paths, of max == 6.Now, to answer [L-R] inclusive queries:1-1 => 1 path available at max=11-2 => 3 paths available at max=2, and none go away for being below L=12-3 => 6 paths available at max=3, minus 1 path available at max=1, = 52-5 => ditto, 6 minus 1 = 51-6 => all 10 paths available at max=6, and none go away for being below L=1Which results all agree with desired sample output.Constraints:1 <= N,Q <= 10^51 <= U,V <= N1 <= W <= 10^91 <= L <= R <= 10^91<<30 = 1,073,741,824*/packagemainimport("fmt""io/ioutil""os""sort""time")funccheck(errerror){iferr!=nil{panic(err)}}funcmain(){start:=time.Now()// stateful data input varsvarstateintvarnintvarn3m3intvarinintvarqintvarq2intvariqint// union varsvaruintvarvintvarwint// query varsvarlintvarrint// Disjoint Set Union [1..n] holds nodes.// Node n holds a slice of representative// AKA parent index, then followers of n.vardsu[][]int// this to postpone operating on edges until all are input.// weights w index map to find a slice of pairs of ints u,vvarwuv=make(map[int][][2]int)// The sum of all DS subset paths grows as edges are added.varpathsint// Ascending list of weight plateaus and their path counts.// When added wp[i]=weight, finished acheiving pc[i]=paths:varwp=make([]int,0)varpc=make([]int,0)// It turns out to feel very natural to have all the funcs// that main calls live inside main to close over its vars.// This function performs a DSU union when adding one edge:union:=func(u,vint){ifu==v{panic("u==v")}pu:=dsu[u][0]pv:=dsu[v][0]ifpu==pv{panic("cyclic")}nu:=len(dsu[pu])nv:=len(dsu[pv])ifnu<nv{// swapu,v=v,upu,pv=pv,punu,nv=nv,nu}// nu is not less than nv// attach pv to bigish pudsu[pu]=append(dsu[pu],dsu[pv]...)for_,iv:=rangedsu[pv]{dsu[iv][0]=pu}dsu[pv]=dsu[pv][:1]// fmt.Printf("union %v & %v :: %#v\r\n", u, v, dsu)// Now compute the impact on pathspaths-=(nu-1)*nu/2paths-=(nv-1)*nv/2paths+=(nu+nv-1)*(nu+nv)/2// fmt.Printf("union %v & %v :: %v\r\n", u, v, paths)}// *ALL* my results were slightly low on next test case 2.// Some OBO etc... // These two sandwich runAllEdges call:sanityCheck1:=func(){// verify that wuv contains N-1 edges.// sudden Aha! I predict it will not...// my map of slices s/b map of references to slices!// so any duplicate weight edge would not get saved.ne:=0for_,suv:=rangewuv{ne+=len(suv)// slice of [u,v] pairs at weight w}// fmt.Println("n", n, "ne", ne) // Ta-Da: n 959 ne 957ifne!=n-1{panic("ne != n-1")}// There was just one duplicate in test case 2:// Now I caught it: 88888:[[541 528] [916 373]]}sanityCheck2:=func(){// not needed now.}// This function finishes inputing phase one to build tree// after having sorted all edges by ascending edge weight:// It builds the ascending wp & pc list to answer queries.runAllEdges:=func(){// process wuv[w] in ascending key w orderkeys:=make([]int,0)forw,_:=rangewuv{keys=append(keys,w)}// fmt.Println("wuv", wuv)sort.Ints(keys)// before all real weights,// add a negative sentinelwp=append(wp,-1)// -1 is below all non-negative weight plateauspc=append(pc,paths)// path count is initially zero, will grow...for_,w:=rangekeys{// fmt.Println("run w", w)// At weight w, union all its (u,v)[i].fori:=0;i<len(wuv[w]);i++{union(wuv[w][i][0],wuv[w][i][1])}// having finished this w,// record path counts for// L-R ranges including w.wp=append(wp,w)pc=append(pc,paths)// fmt.Println("w", w, "paths", paths)}// after all real weights,// add a ~maxint sentinelwp=append(wp,1<<30)pc=append(pc,paths)// fmt.Println("wp", wp)// fmt.Println("pc", pc)// on the given sample data:// wp [-1 1 2 3 6 1073741824]// pc: [0 1 3 6 10 10]}// This function is inputing phase one to build tree.// Add input UVW to a map[w]->list(u,v) to run later.addEdgeUVW:=func(){// Note this func inside main closes over u,v,w:// _ = u// _ = v// _ = wsp,ok:=wuv[w]ifok{// Finally, here was my downfall:// Assigning back to the copy sp,// did not add to original wuv[w]// WRONG: sp = append(sp, [2]int{u, v})wuv[w]=append(sp,[2]int{u,v})}else{wuv[w]=append(make([][2]int,0),[2]int{u,v})}// fmt.Printf("%#v\r\n", wuv)}// This function is inputing phase two to answer queries.answerLR:=func(){// The main stdin parsing loop set l and r values for me:_=l_=r// fmt.Println("\r\nQuerying L,R:", l, r)// My original very-mind-troubling plan was to do// a binary search in wp for both of l and r, and// then interpolate for present versus missing wp.// It produced answers that were all slightly low.// New plan is to store an entire range of 10^5 w.// Today's new approach is invalid: 10^9 not 10^5.// Where did that old code go? Ahhh, found it!....// N.B. L test uses ">="i:=sort.Search(len(wp),func(sint)bool{returnwp[s]>=l})// fmt.Println("searching L=", l, "gave i=", i, "wp[i]=", wp[i])// fmt.Println("Subtracting at i-1=", i-1, "wp[i-1]=", wp[i-1], "pc[i-1]=", pc[i-1])// N.B. R test uses ">"j:=sort.Search(len(wp),func(sint)bool{returnwp[s]>r})// fmt.Println("searching R=", r, "gave j=", j, "wp[j]=", wp[j])// fmt.Println("Adding at j-1=", j-1, "wp[j-1]=", wp[j-1], "pc[j-1]=", pc[j-1])fmt.Println(pc[j-1]-pc[i-1])// "ANSWER:"}// Atoi accumulatorvaraccuint// This function uses the next input number from stdin parse.// It statefully processes n, q, then n triplets, q doublets.useAccu:=func(){// fmt.Println("use", accu)switchstate{case0:// initial state, reading nn=accu// fmt.Println("n", n)n3m3=3*n-3// N nodes means N-1 edges{// initialize for n nodesdsu=make([][]int,1+n)// 1-up, slot 0 unusedfori:=1;i<=n;i++{dsu[i]=[]int{i}}}state++breakcase1:// second state, reading qq=accu// fmt.Println("q", q)q2=2*qstate++breakcase2:// third state, reading n x tripletsswitchin%3{case0:u=accu// fmt.Println("u", u)breakcase1:v=accu// fmt.Println("v", v)breakcase2:w=accu// fmt.Println("w", w)addEdgeUVW()break}in++ifin==n3m3{// before advancing state,// process those n inputs.sanityCheck1()runAllEdges()sanityCheck2()state++}breakcase3:// third state, reading q x doubletsswitchiq%2{case0:l=accu// fmt.Println("l", l)breakcase1:r=accu// fmt.Println("r", r)answerLR()break}iq++ifiq==q2{// Just anal I guess.// fmt.Println("EOF")state++}breakcase4:default:panic(state)break}}// Finally, the main DIY stdin, atoi loop here:sb,err:=ioutil.ReadAll(os.Stdin)check(err)varinNumboolfor_,b:=rangesb{ifb<byte('0'){// whitespaceifinNum{useAccu()accu=0inNum=false}}else{// digitaccu=accu*10+int(b-byte('0'))inNum=true}}// At EOF w/o NL, a HackerRank trait:ifinNum{useAccu()}_=start// 7 ms on ~ 1K, 1K data: fmt.Println(time.Since(start).Nanoseconds(), "ns")}
Cookie support is required to access HackerRank
Seems like cookies are disabled on this browser, please enable them to open this website
Super Maximum Cost Queries
You are viewing a single comment's thread. Return to all comments →
in Go/golang, passes 100%