As DABA said, the ladder is pretty much the same, but the data tables have changed.
Gone are the various tables (I:, O:, B3:, N7:, etc). Instead, there is one big "table" of "Controller-scoped" tags. These are referenced by name, not number, and you can give them whatever name helps you best. (More on that in a bit).
I/O
The I/O tags are based on the name of the rack in which the I/O card resides. The rack in which the PLC processor lives is called "LOCAL". Remote racks can be anything you want.
Actual I/O addresses would then take the form of "Local:6:I.Data.2, for the channel 2 discrete input point in slot 6, for example. Like with a SLC, 5000 adds all the relevant data when you add the module into the PLC configuration.
DINTs
Your most common data type to store integers is now the 32-bit DINT ("Double Integer"). No longer do you need worry about exceeding 32767; you now can manage values of over 2.1 billion. This makes life much easier.
Timers
Gone are the various time-bases. Everything is in milliseconds. But because .PRE and ACC are now DINT datatypes, 2.1 billion milliseconds translates to about 25 days, rather than the 9-hour limit that 32767 sec gave you.
Arrays
In the SLC, you may have taken advantage of the fact that registers were next to each other, and used indirect addressing and file instructions (FAL, FSC, COP, FLL) to efficiently manage data.
In a tag-based system, you do the same thing by defining a tag as an array ("DINT[256]") data type. You could create an array tag, called N7, and now, where in the SLC you might reference N7:13 you would reference N7[13]. In fact, that's exactly what the SLC-CLX conversion tool does.
But you don't really need to. I don't know if you've ever run into times in working with arrays in the SLC where you had a "file" from something like F8:50-75 and were pointing to it with an indirect address, but later wanted to increase the size of that array to 50 elements, only to discover in your "Usage Table" that F8:76+ were used elsewhere in the program, so you couldn't without a lot of rewriting.
Usage Table
That's probably the biggest culture shock when going from 500 to 5000. It doesn't exist. That's because you don't have a need to find unused memory to store data, you create that memory instead.
You can find out if whole tags are not referenced in the code (to clean up memory allocation), and there are even tricks to find out if what elements haven't been used yet, if you like to do things like create a "Onshots" DINT and take unique bits from within that word. But there's nothing like the old Usage view of a data table.
Programs and Program Tags
In the SLC, you could put all your code in a routine called LAD2, or you could break up your code into functional groups, putting them into separate routines (LAD3, LAD4) and call them with JSRs.
You can still do all that with 5000, but additionally, you can organize your code even more, with the creation of multiple "Programs", each of which have their own children routines under them.
That way, you can have a "LINE1" program, with "MOTORS", "PHOTOEYES", and other routines under it, and a "LINE2" program, with its own "MOTORS", etc., routines under them. You don't have to, but you can. It makes things easier to find, and identical things can be identical, with maybe only a simple search-replace of tag names.
Each Program has its own collection of locally-scoped tags as well. This feature actually exists in the SLC, where you can assign a data-table to only being exposed to a particular routine, but no one ever used it (that I ever saw). Here, however, it can be very useful. Controller-scoped tags are exposed to every program; program-scoped tags are scoped only to that program.
So if you were to have a "Oneshots" DINT tag in your LINE1 program, and also have a "Oneshots" tag in your LINE2 program, when you copy your code for LINE1 into LINE2, each [ONS] instruction is only referring to its local tag, and doesn't interfere with the other line. You didn't have to "find new unused addresses" for the "new" oneshots.
By keeping all the "placeholder" tags, for oneshots, interim calculation holding registers, certain timers, and so forth in the Program instead of the Controller, makes the Controller tag folder a lot less cluttered.
UDTs
In addition to the "Atomic" types that DABA meantioned (BOOL, DINT, REAL, etc.), and arrays above, you can create your own data type.
This can greatly improve the organization of the program, because you have all the elements that you need wrapped up in a single tag.
You're actually quite used to this concept already. A T4 data type in the SLC consists of 2 integers (.PRE & .ACC), and 3 bits (.DN, .EN, & .TT). With UDTs, you create a similar mix of other data types, but with anything you want.
For example, if you have 10 motors, and each motor can be controlled via the HMI by having an Auto and Manual Mode, with a Start and Stop command, an output and an aux contact, failure alarms, and so on, rather than make a bunch of tags for each motor ("M101_Start", "M101_Stop", "M101_Oper", etc), you can create a single tag ("M101") of a "Motor" data type that has elements ("M101.Start", ""M101.Stop", etc.) for what you want.
If you create a routine for M101 that does all the start/stop logic, mode & alarm handling and so on, now all you have to do is create a tag ("M201"), copy the whole routine to a new one, search/replace M101 for M201, and the only thing left is to tie the in the different I/O points.
Asynchronous I/O Scans
In the SLC, there was one execution thread: Read Inputs >> Scan Logic >> Write Outputs >> Do Housekeeping >> ((repeat)).
There could also be an STI routine that could periodically interrupt this sequence with the execution of its logic.
The CLX handles the I/O updates periodically, outside of logic scan. In theory, this could cause problems, because a --| |-- referencing an input module could be true on one rung but not on the next, rung if the I/O scan happened to arrive between the logic scans of the two rungs.
The hype about this is largely overblown, IMO. HMI communication has always been asynchronous to scan, but only rarely have I see that cause problems. But people will insist that you "have to" buffer I/O --- that is, map the I/O to internal registers, using the real address once and only once.
That's not a bad thing to do, mind you, especially if using UDTs anyway. But it is not strictly required. Just be aware of the asynchronous nature of I/O. If the only thing you use the Aux contact input is for alarming, and you compare both the On and Off state to your motor starter coil to run a "failed" timer, nothing is going get screwed up because for one scan both the XIO and XIC were true. The timer will only accumulate a few milliseconds, not enough to cause a "false alarm".
There are a zillion more tricks, trips, and traps, but this is more than enough to get you started.
Enjoy, good luck, and Merry Christmas.