I mean, i am not getting why/how it is pointing to string "three"?
0x65fdf0: 0x6f 0x6e 0x65 0x00 0x00 0x00 0x00 0x00
0x65fdf8: 0x74 0x77 0x6f 0x00 0x00 0x00 0x00 0x00
0x65fe00: 0x74 0x68 0x72 0x65 0x65 0x00 0x00 0x00
Maybe this makes it more clear. The array s might look like the following (see map above) where each line represents one of the strings, the first is "one", the second "two" and the third "three".
After initialization p points to the last row. If you print p as string all characters will be printed until the \0 termination is found. When incrementing p it will move one position to the right, not down! So it is basically pointing to s[2] + 1 which is the second element in the last row, representing the "h". When printing as string, again all characters will be printed until \0 is reached.
The interesting part however is the side effect of ++p as parameter, which triggers ub/idb.
Depending on the compiler either "three" or " hree" will be printed.
Obviously, the last four letters will be "hree" since the second argument will point to the "h" for sure.
C and C++ do not specify the order of argument evaluation, which means every compiler is free to either compute *(p-1) first and then ++p, or the other way around. Depending on the side affect of the incrementation the result may vary, letting *(p-1) either point to a \0 symbol (last element in second row) or to the "t" of "three".