其实算不上什么题解……有两道题不会做……只是觉得D题挺有意思所以就写了个题解……
UPD:A题会做了好开心~
A:
题意:定义一个电阻为:1、一个单位电阻;2、一个电阻与一个单位电阻串联;3、一个电阻与一个单位电阻并联。问最少需要多少个单位电阻拼出一个阻值为a/b的电阻。a,b<=10^18。
题解:假设我们可以用k个单位电阻组成一个阻值为a/b的电阻,那么串联可以得到一个(a+b)/b的电阻,并联可以得到一个a/(a+b)的电阻。那么假如a/b>=1,我们就先不断串联使得a/b<1,此时并联,得到的新的阻值就应为a/(b-a)。我们注意到这实际上就是一个更相减损术的过程……于是答案就是做gcd的时候做减法的次数。复杂度O(log(max(a,b))。
B:
题意:有两根线缠在了一起,一共n个交叉。告诉你在每个交叉的位置是哪根线在上,问能不能在不移动线的端点的情况下解开两根线。
题解:从左到右扫,同时维护一个栈。如果当前的交叉和栈顶的交叉是同一根线,那么就弹出栈顶,否则把这个交叉压入栈。最后如果栈为空就能做到。
C:
题意:一条数轴上有n个磁头和m个标记。每一秒钟一个磁头可以向左或者向右移动一格。磁头之间不互相影响,而且可以同时移动。如果磁头扫到了某个标记,就算读取了这个标记。问最少要花多少时间读取所有标记。
题解:首先在最优方案中一定是一个磁头负责连续一段的标记。由于要最小化最大值,所以可以二分答案。每个磁头可以先向左走再折回向右,或者先向右再折回向左。记录当前已经读取了最左侧的多少个标记,那么这个磁头负责的就应该是目前最左侧尚未读取的标记到尽量右侧的标记。可以O(n)地单调扫。那么总复杂度就是O(nlogW)。
D:
题意:给定一棵以1号点为根的有根树,共n个节点。有m次共3种操作:1、将某个节点的子树染黑;2、将某个节点及其所有祖先染白;3、询问某个点的颜色。初始时所有节点为白色。n,m<=500000。
题解:虽说n有50w,但做法还是nlogn的。而且这题有许多有意思的做法……这里我讲三种。
解法一:我们用LCT维护这棵树。对于2操作,直接把到根的链染白;对于1操作,将这个点染黑。在查询的时候,如果这个点存在一个黑色祖先,那么这个点就是黑色的,否则是白色的。
解法二:我们可以离线回答询问。先只考虑染黑操作,用线段树维护DFS序,并维护每个点的颜色以及最近一次被染色的时间,查询时记录下时间。然后再只考虑染白操作,同样用线段树维护,只染白一个点,查询时查子树中是否有白色点,以及最近一次的时间。最后输出答案时判断这个点是否被1和2操作影响了,如果被两种操作影响了那么就看哪个在先哪个在后。
解法三:注意到如果一个点是黑色的,那么他的整棵子树都应该是黑色的,我们可以直接用这个方法判断一个点的颜色。那么对于2操作直接将一个点染白,对于1操作首先判断该点是否是黑色的,如果不是那么将其父亲染白,之后再将整棵子树染黑。用线段树维护DFS序,并维护每段的颜色以及为黑色的点的数目,并预处理子树大小即可。
E就不会了……