I don’t think this has anything to do with autograd, but rather just the fact that when you assign a variable directly (rather than an index range with a preallocated tensor), you essentially get a view of the same memory that has the same underlying storage. For example, if you add
print("w ptr: ", w.storage().data_ptr())
print("a ptr: ", a.storage().data_ptr())
print("b ptr: ", b.storage().data_ptr())
print("c ptr: ", c.storage().data_ptr())

after the code, you will see something like:
w ptr:  16615296
a ptr:  16615296
b ptr:  16615296
c ptr:  57524864

which explains why the variables change the way that they do.
For example, if you change a=w[0] to a[:]=w[0] you can see this change.
w:  tensor([0.9990, 1.9990, 2.9990, 3.9990], requires_grad=True)
a:  tensor([1])
b:  tensor([0.9990, 1.9990], grad_fn=<AsStridedBackward>)
c:  tensor([1, 3])
w ptr:  42055552
a ptr:  41892352
b ptr:  42055552
c ptr:  82965120