I 君的商店
不知道这道题是怎么被人想出来的,tql
题意:
有一张图,(n) 个点,(m) 条边,但是你不知道这张图具体的模样,你可以执行 4 种操作来确定这张图:
- 每个点初始有一个状态 (0)
- ( m modify(x)),修改点 (x) 的状态以及其所有与其有边的点的状态。
- ( m query(x)),查询点 (x) 的状态。
- ( m report(x,y)),告诉交互库存在一条 (x o y) 的无向边,并储存之。
- ( m check(x)),检查 (x) 的所有出边是否均被储存。
其中 (1,2,4) 操作均有次数限制,令 (L_m,L_q,L_c) 依次表示其操作次数限制。
部分分:
- 暴力即可。
- (Nle 2cdot 10^5,M=N/2,L_m,L_qle 18N,L_c=0)
- (Nle 2cdot 10^5,M=N-1,L_m,L_qle 18N),保证为链。
- 同 (3),保证为树。
- 保证为内向树。
- 一张图,(Nle 2cdot 10^5,Mle 3cdot 10^5,L_q,L_mle 50N)。
- (2) 类数据
考虑按照二进制位进行拆位处理,如果当前位是 (1) 那么修改它,然后依次查询。
如果这个点连的点在当前位不同,那么其状态一定改变。
否则一定不变,那么可以直接算出来这个点的对应点。
- (3) 类数据
发现做法 (2) 实际上可以得到这个点连出去的点的编号的异或和。
找 (0) 号的出边,这个可以 (mathcal O(n)) 确定,接下来可以直接递推两边的结果。
- (4) 类数据
考虑如何在树上确定,类似 (2) 的处理,接下来我们仍然先处理 (0) 的出边是谁,考虑如果知道了叶子节点是谁,那么根据我们得到的信息可以轻易的还原树。
所以每次修改 (x),然后查询 (f_x) 是否改变即可得到所有的叶子节点。
大概是一个剥叶子的思路。
- (5) 类数据
注意到父亲是单调的,考虑二分一个 (x),然后将 ([0,x)) 均进行修改,那么如果 (uin [x,n)) 的状态改变了,则其与这个区间存在连边。
对于所有点都需要求,显然可以换成整体二分。
- (6) 类数据
我们先随机一个排列,如果这个点往在它前面的点连边数为奇数,那么设这个点为关键点。
可以证明,关键点的数量期望为 (frac{n}{3})
我们考虑一个算法,使得每轮可以至少找出关键点向前连边的一条边。
考虑二分一个 (x),然后依次操作 (a_{0sim x-1}),接着查询所有点,显然处于后面的点如果状态改变,说明其往前面的集合至少有一条边。
然后将二分换成类似于整体二分的处理,注意到如果一个集合与你的连边为偶数,那么在处理这个集合的时候我们将所有点都进行 modify 对你依然没有影响,不过当然也可以暴力点修改后再改回来,于是显然这样可以筛出 (frac{n}{3}) 条边,这玩意儿的查询/修改次数显然为 (T(n)=mathcal O(nlog n) +T(frac{2n}{3})=mathcal O(3nlog n))
当然,我们显然在单次操作时要去除已操作的边的影响,这样才可以保证单次至少可以筛出 (frac{n}{3}) 条其他边。
通过 check 操作进行适当剪枝可以在 (mathcal O(50N)) 的查询通过本题。