I have a vanity domain, and used to be able to use GMail to send email as that domain [1], and forward received mail from that domain back to GMail.
But with SPF, DKIM, and DMARC (or something), this has broken and such received email gets marked as spam and/or phishing.
I don't know how to fix the forwarding/receiving flow [2], because GMail will see the message coming from an arbitrary source, but being forwarded by an intermediate (my hosting provider's forwarding email server) which will fail its integrity checks.
I have not been able to understand how to solve this. Clearly, forwarding servers aren't a well-regarded use-case in this new era of verified email flow.
Also, I'm not just talking about GMail. I used to do forwarding for my family who used a variety of providers, so I can't just switch to GMail (via Google Domains) for my entire domain.
[1] GMail still offers that feature, under Settings->Accounts and Import->"Send mail as"
[2] the sending flow is easy: just add gmail's SPF to my own domain's
There are exceptions. The famous shootout scene from "Heat" does a surprisingly good job at conveying just how deafening gunfire really is close up, for a movie. Although even that is much milder than it would be IRL, due to use of blanks and the aforementioned equipment limitations.
https://www.youtube.com/watch?v=ZL9fnVtz_lc (shooting starts around 4:20)
The video hyperlinked below is a fascinating debunking of most other "primitive" channels.
The goal is a data structure where you can perform operations like "a and b are in the same set", "b and c are in the same set" and then get answers to questions like "are a and c in the same set?" (yes, in this example.)
The implementation starts out pretty obvious - a tree where every element either points at itself or some thing it was merged with. To check if two elements are in the same set, check if they have the same parent. Without analyzing it, it sounds like you'll average findRoot() performance of O(log(n)), worst-case O(n).
There are a couple of simple optimizations you can do to this structure, the type of things that seem like they shouldn't end up affecting asymptotic runtime all that much. The first is that, whenever you find a root, you can re-parent all the nodes you visited on the way to that root, so they'll all be quicker to look up next time. The other is that you keep track of the size of sets, and always make the larger set be the parent of the smaller.
And neither of those actually do anything impressive alone, but if you use both, the algorithm suddenly becomes incredibly fast, with the slowest-growing (non-constant) complexity I've ever heard of: O(the inverse of the Ackermann function(n)). Or, for any reasonable N, O(4 or less).