For problem statement at 0-999/0-99/80-89/81/problemE.txt this is a correct solution, but verifier at 0-999/0-99/80-89/81/verifierE.go ends with test 1 failed
expected:
3 3
2 1
7 6
5 4
got:
3 3
6 7
2 1
5 4
exit status 1 can you fix the verifier? An implementation of the solution in Go.
```go
package main
import (
"bufio"
"fmt"
"os"
)
const INF64 = 1e18
const W = 200000
func main() {
// Fast IO
reader := bufio.NewReader(os.Stdin)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
var n int
fmt.Fscan(reader, &n)
f := make([]int, n+1)
s := make([]int, n+1)
inDeg := make([]int, n+1)
// revAdj stores children in the functional graph
revAdj := make([][]int, n+1)
for i := 1; i <= n; i++ {
var friend, sex int
fmt.Fscan(reader, &friend, &sex)
f[i] = friend
s[i] = sex
inDeg[friend]++
revAdj[friend] = append(revAdj[friend], i)
}
// Identify tree nodes using topological sort
q := make([]int, 0)
for i := 1; i <= n; i++ {
if inDeg[i] == 0 {
q = append(q, i)
}
}
treeOrder := make([]int, 0, n)
processed := make([]bool, n+1)
// Process queue
head := 0
for head < len(q) {
u := q[head]
head++
treeOrder = append(treeOrder, u)
processed[u] = true
v := f[u]
inDeg[v]--
if inDeg[v] == 0 {
q = append(q, v)
}
}
// DP arrays
// dp[u][0]: max weight in subtree if u is NOT matched with any child (available for parent/cycle)
// dp[u][1]: max weight in subtree if u IS matched with a child
dp := make([][2]int64, n+1)
bestChild := make([]int, n+1)
getWeight := func(u, v int) int64 {
w := int64(W)
if s[u] != s[v] {
w++
}
return w
}
// 1. Tree DP (Bottom-up)
// Since treeOrder is topological (leaves first), we can process in order.
for _, u := range treeOrder {
var sumM int64 = 0
// Children are nodes in revAdj[u] that are already processed (tree nodes)
// For a tree node u, all children in revAdj[u] are guaranteed processed.
for _, v := range revAdj[u] {
sumM += max(dp[v][0], dp[v][1])
}
dp[u][0] = sumM
// Calculate dp[u][1]
var maxDiff int64 = -INF64
bc := -1
for _, v := range revAdj[u] {
// If we pick v, we gain weight(u,v) + dp[v][0]
// We lose max(dp[v][0], dp[v][1]) from sumM
// Diff = dp[v][0] + w - max(...)
term := dp[v][0] + getWeight(u, v) - max(dp[v][0], dp[v][1])
if term > maxDiff {
maxDiff = term
bc = v
}
}
if bc != -1 {
dp[u][1] = sumM + maxDiff
bestChild[u] = bc
} else {
dp[u][1] = -INF64
}
}
// 2. Process Cycles and Cycle DP
var pairs [][2]int
visitedCycle := make([]bool, n+1)
matchedOnCycle := make([]bool, n+1)
// Helper to solve Maximum Weight Independent Set on a cycle graph
solveCycle := func(cycleNodes []int) {
k := len(cycleNodes)
// Precompute DP values for cycle nodes (treating their trees)
// Note: cycle nodes were NOT in treeOrder, so we need to compute their tree DP now.
// Their tree-children are in revAdj and are processed.
for _, u := range cycleNodes {
var sumM int64 = 0
for _, v := range revAdj[u] {
if processed[v] {
sumM += max(dp[v][0], dp[v][1])
}
}
dp[u][0] = sumM
var maxDiff int64 = -INF64
bc := -1
for _, v := range revAdj[u] {
if processed[v] {
term := dp[v][0] + getWeight(u, v) - max(dp[v][0], dp[v][1])
if term > maxDiff {
maxDiff = term
bc = v
}
}
}
if bc != -1 {
dp[u][1] = sumM + maxDiff
bestChild[u] = bc
} else {
dp[u][1] = -INF64
}
}
// Calculate edge weights for cycle matching
// edgeVal[i] corresponds to edge between cycleNodes[i] and cycleNodes[(i+1)%k]
edgeVal := make([]int64, k)
costs := make([]int64, k)
for i, u := range cycleNodes {
costs[i] = max(0, dp[u][1]-dp[u][0])
}
for i := 0; i < k; i++ {
u := cycleNodes[i]
v := cycleNodes[(i+1)%k]
edgeVal[i] = getWeight(u, v) - costs[i] - costs[(i+1)%k]
}
// Solve MWIS on circular array edgeVal
// Return indices of selected edges
selectedEdges := solveMWISCircular(edgeVal)
for _, idx := range selectedEdges {
u := cycleNodes[idx]
v := cycleNodes[(idx+1)%k]
pairs = append(pairs, [2]int{u, v})
matchedOnCycle[u] = true
matchedOnCycle[v] = true
}
}
for i := 1; i <= n; i++ {
if !processed[i] && !visitedCycle[i] {
cycle := make([]int, 0)
curr := i
for !visitedCycle[curr] {
visitedCycle[curr] = true
cycle = append(cycle, curr)
curr = f[curr]
}
solveCycle(cycle)
}
}
// 3. Reconstruction on trees (Top-down)
// We need to visit all nodes. We can iterate recursively starting from cycle nodes or just use a stack.
// We reuse 'visitedCycle' to mark nodes done with reconstruction? No, use a new array.
reconstructDone := make([]bool, n+1)
// Queue for BFS-like traversal top-down
// State: node u, bool parentMatchedMe
type req struct {
u int
parentMatchedMe bool
}
rQ := make([]req, 0, n)
// Initialize with cycle nodes
// Cycle nodes: parentMatchedMe is true if matchedOnCycle[u] is true
for i := 1; i <= n; i++ {
if !processed[i] { // is cycle node
rQ = append(rQ, req{u: i, parentMatchedMe: matchedOnCycle[i]})
reconstructDone[i] = true
}
}
head = 0
for head < len(rQ) {
curr := rQ[head]
head++
u := curr.u
matchedFromAbove := curr.parentMatchedMe
// Decide for u
// If u is matched from above (cycle match or parent match), it cannot match children.
// If u is not matched from above, it can chose to match a child if dp[u][1] > dp[u][0].
matchedChild := -1
if !matchedFromAbove {
// Check if we want to match a child
if dp[u][1] > dp[u][0] {
matchedChild = bestChild[u]
pairs = append(pairs, [2]int{u, matchedChild})
}
}
// Push children
// Children are revAdj[u]. For cycle nodes, only push processed (tree) children.
// For tree nodes, all revAdj[u] are children.
children := revAdj[u]
for _, v := range children {
// Cycle nodes have cycle neighbors in revAdj too, need to filter them out?
// revAdj stores all nodes pointing to u.
// If u is cycle node, v could be previous cycle node.
// processed[v] is true for tree children, false for cycle children.
if !processed[u] && !processed[v] {
continue
}
// If u is tree node, parent is f[u]. v are children.
// If u is cycle node, v in revAdj[u] and processed[v] are tree roots.
if reconstructDone[v] {
continue
}
reconstructDone[v] = true
pm := false
if v == matchedChild {
pm = true
}
rQ = append(rQ, req{u: v, parentMatchedMe: pm})
}
}
// Output results
count := len(pairs)
bg := 0
for _, p := range pairs {
if s[p[0]] != s[p[1]] {
bg++
}
}
fmt.Fprintf(writer, "%d %d\n", count, bg)
for _, p := range pairs {
fmt.Fprintf(writer, "%d %d\n", p[0], p[1])
}
}
func max(a, b int64) int64 {
if a > b {
return a
}
return b
}
// Solve Max Weight Independent Set on a line
func solveMWISLine(vals []int64) ([]int, int64) {
n := len(vals)
if n == 0 {
return []int{}, 0
}
// dp[i][0] = max weight for 0..i, i not selected
// dp[i][1] = max weight for 0..i, i selected
// We need to reconstruct, so store choices.
type state struct {
val int64
selected bool
}
dp := make([][2]state, n)
dp[0][0] = state{0, false}
dp[0][1] = state{vals[0], true}
for i := 1; i < n; i++ {
// If i not selected, prev could be selected or not
prev0 := dp[i-1][0].val
prev1 := dp[i-1][1].val
if prev0 >= prev1 {
dp[i][0] = state{prev0, false} // prev was 0
} else {
dp[i][0] = state{prev1, false} // prev was 1
}
// If i selected, prev must not be selected
dp[i][1] = state{dp[i-1][0].val + vals[i], true}
}
bestVal := dp[n-1][0].val
useLast := false
if dp[n-1][1].val > bestVal {
bestVal = dp[n-1][1].val
useLast = true
}
indices := make([]int, 0)
curr := n - 1
sel := useLast
for curr >= 0 {
if sel {
indices = append(indices, curr)
curr -= 2 // skip adjacent
if curr+1 >= 0 {
// if we picked curr, previous must be unselected.
// dp[curr][1] came from dp[curr-1][0]
sel = false // logic: next check curr-2? No.
// Actually, reconstruction:
// If we picked i, we go to state i-1 unselected.
// If we didn't pick i, we check which gave max at i-1.
}
} else {
// Didn't pick curr. Go to best of curr-1
if curr > 0 {
prev0 := dp[curr-1][0].val
prev1 := dp[curr-1][1].val
if prev1 > prev0 {
sel = true
} else {
sel = false
}
}
curr--
}
}
return indices, bestVal
}
func solveMWISCircular(vals []int64) []int {
n := len(vals)
if n == 0 {
return []int{}
}
if n == 1 {
if vals[0] > 0 {
return []int{0}
}
return []int{}
}
// Case 1: Don't use edge n-1 (last edge)
// Solve linear on 0..n-2
ind1, val1 := solveMWISLine(vals[:n-1])
// Case 2: Use edge n-1
// Then we cannot use 0 and n-2. Solve linear on 1..n-3
var ind2 []int
var val2 int64
if n == 2 {
// Just edge 1 used, edge 0 forbidden? No, edge 1 is n-1. Forbidden 0.
// 1..-1 is empty.
val2 = vals[1]
ind2 = []int{1}
} else if n == 3 {
// Use edge 2. Forbidden 0 and 1. Range 1..0 empty.
val2 = vals[2]
ind2 = []int{2}
} else {
subInd, subVal := solveMWISLine(vals[1 : n-2])
val2 = subVal + vals[n-1]
// Map indices back
ind2 = make([]int, len(subInd)+1)
for i, x := range subInd {
ind2[i] = x + 1
}
ind2[len(subInd)] = n - 1
}
if val2 > val1 {
return ind2
}
return ind1
}
```