Suppose I have
val foo : Seq[Double] = ...
val bar : Seq[Double] = ...
and I wish to produce a seq where the baz(i) = foo(i) + bar(i). One
A lazy list isn't a copy of a list - it's more like a single object. In the case of a lazy zip implementation, each time it is asked for the next item, it grabs an item from each of the two input lists and creates a tuple from them, and you then break the tuple apart with the pattern-matching in your lambda.
So there's never a need to create a complete copy of the whole input list(s) before starting to operate on them. It boils down to a very similar allocation pattern to any application running on the JVM - lots of very short-lived but small allocations, which the JVM is optimised to deal with.
Update: to be clear, you need to be using Streams (lazy lists) not Lists. Scala's streams have a zip that works the lazy way, and so you shouldn't be converting things into lists.
Ideally your algorithm should be capable of working on two infinite streams without blowing up (assuming it doesn't do any folding, of course, but just reads and generates streams).