IMO the easiest way is to name the form fields dynamically using a counter. So each set of fields will be numbered from 1 to N:
CODE
form.firstName1, form.lastName1
form.firstName2, form.lastName2
...
form.firstNameN, form.lastNameN
Cfquery's currentRow variable makes an good counter:
CODE
<form ...>
<cfoutput query="yourQuery">
<input type="text" name="firstName#currentRow#" value="#firstName#">
<input type="text" name="lastName#currentRow#" value="#lastName#">
....
</cfoutput>
</form>
Outside the query, save the total number of records in a hidden form field. You can obtain the total from cfquery's recordCount variable.
Then on your processing page, use a from/to loop to extract each set of values. Assuming your form uses method="post", the fields will be stored in the FORM structure. To retrieve the values use array notation:
#form["yourFieldName"& counterNumber]#
CODE
<cfloop from="1" to="#form.totalNumberOfRecords#" index="counter">
<!--- extract the values of the dynamic form fields --->
<cfset variables.firstName = form["firstName"& counter]>
<cfset variables.lastName = form["lastName"& counter]>
.... your query goes here ...
</cfloop>
Once you have extracted the values, the rest is just constructing your INSERT or UPDATE query.