instead of passing in the scalar 'a', pass in a hashref with your data, and the changes will persist:
use Template;
my $vars = { a => 0 };
my $tt2 = Template->new();
my $template = "[% SET data.a=data.a+1 %] A is now [% data.a %]\n";
$tt2->process( \$template, { data => $vars } ) for 1..5;
Update: My guess, based just on the behavior seen in my post and the OP, is that TT passes the data by value. So in the OP, the 'a' that gets modified isn't the real 'a'. In my post, we're not modifying the value (address) of 'data', but are deferencing it and then changing values, so they appear to persist.