First, you need to ensure your package.xml contains at least what you are deploying. It may contain more, but not less.
<types>
<members>Class1</members>
<members>Class2</members>
<members>Class3</members>
<name>ApexClass</name>
</types>
UPDATE: It is even easier to do this:
<types>
<members>*</members>
<name>ApexClass</name>
</types>
Next, setup an ant target in your build.xml which looks something like this:
<target name="QADeployClass1And2">
<delete file="deploy.zip"/>
<zip destfile="deploy.zip">
<fileset dir="src" includes="classes/Class1.*"/>
<fileset dir="src" includes="classes/Class2.*"/>
<fileset dir="src" includes="package.xml"/>
</zip>
<sf:deploy zipFile="deploy.zip" allowMissingFiles="true"
username="user@org.com.qa" password="**********"
serverurl="https://test.salesforce.com"/>
<delete file="deploy.zip"/>
</target>
When you run this target you will deploy only Class1.cls and Class2.cls. I also find it useful to place the username, password and serverurl on the target so that I can use a different ant target for each target org without having to switch out the build.properties file.
I use the zipfile approach (1) because this allows me to easily and centrally control which files go into the payload. If you wish to use a folder with deployRoot you need to make a temporary folder and copy in the files you need:
<target name="deploy1">
<delete>
<fileset dir=".\deploy\classes" includes="**/*.*"/>
</delete>
<copy file="deploy\package1.xml" tofile="deploy\package.xml"/>
<copy todir=".\deploy\classes">
<fileset dir=".\src\classes\" includes="Class1.*"/>
<fileset dir=".\src\classes\" includes="Class2.*"/>
</copy>
<sf:deploy allowMissingFiles="true" username="${sf.username}" password="${sf.password}" serverurl="${sf.serverurl}" deployRoot="deploy"/>
</target>
In this example you could setup package1.xml to only include the files you want to deploy and it will overwrite package.xml when you run this ant target thus making allowMissingFiles="true" superfluous.