NOI2019 I 君的商店

I 君的商店

不知道这道题是怎么被人想出来的,tql

题意:

有一张图,\(n\) 个点,\(m\) 条边,但是你不知道这张图具体的模样,你可以执行 4 种操作来确定这张图:

  • 每个点初始有一个状态 \(0\)
  1. \(\rm modify(x)\),修改点 \(x\) 的状态以及其所有与其有边的点的状态。
  2. \(\rm query(x)\),查询点 \(x\) 的状态。
  3. \(\rm report(x,y)\),告诉交互库存在一条 \(x\to y\) 的无向边,并储存之。
  4. \(\rm check(x)\),检查 \(x\) 的所有出边是否均被储存。

其中 \(1,2,4\) 操作均有次数限制,令 \(L_m,L_q,L_c\) 依次表示其操作次数限制。

部分分:

  1. 暴力即可。
  2. \(N\le 2\cdot 10^5,M=N/2,L_m,L_q\le 18N,L_c=0\)
  3. \(N\le 2\cdot 10^5,M=N-1,L_m,L_q\le 18N\),保证为链。
  4. \(3\),保证为树。
  5. 保证为内向树。
  6. 一张图,\(N\le 2\cdot 10^5,M\le 3\cdot 10^5,L_q,L_m\le 50N\)
  • \(2\) 类数据

考虑按照二进制位进行拆位处理,如果当前位是 \(1\) 那么修改它,然后依次查询。

如果这个点连的点在当前位不同,那么其状态一定改变。

否则一定不变,那么可以直接算出来这个点的对应点。

  • \(3\) 类数据

发现做法 \(2\) 实际上可以得到这个点连出去的点的编号的异或和。

\(0\) 号的出边,这个可以 \(\mathcal O(n)\) 确定,接下来可以直接递推两边的结果。

  • \(4\) 类数据

考虑如何在树上确定,类似 \(2\) 的处理,接下来我们仍然先处理 \(0\) 的出边是谁,考虑如果知道了叶子节点是谁,那么根据我们得到的信息可以轻易的还原树。

所以每次修改 \(x\),然后查询 \(f_x\) 是否改变即可得到所有的叶子节点。

大概是一个剥叶子的思路。

  • \(5\) 类数据

注意到父亲是单调的,考虑二分一个 \(x\),然后将 \([0,x)\) 均进行修改,那么如果 \(u\in [x,n)\) 的状态改变了,则其与这个区间存在连边。

对于所有点都需要求,显然可以换成整体二分。

  • \(6\) 类数据

我们先随机一个排列,如果这个点往在它前面的点连边数为奇数,那么设这个点为关键点。

可以证明,关键点的数量期望为 \(\frac{n}{3}\)

我们考虑一个算法,使得每轮可以至少找出关键点向前连边的一条边。

考虑二分一个 \(x\),然后依次操作 \(a_{0\sim x-1}\),接着查询所有点,显然处于后面的点如果状态改变,说明其往前面的集合至少有一条边。

然后将二分换成类似于整体二分的处理,注意到如果一个集合与你的连边为偶数,那么在处理这个集合的时候我们将所有点都进行 modify 对你依然没有影响,不过当然也可以暴力点修改后再改回来,于是显然这样可以筛出 \(\frac{n}{3}\) 条边,这玩意儿的查询/修改次数显然为 \(T(n)=\mathcal O(n\log n) +T(\frac{2n}{3})=\mathcal O(3n\log n)\)

当然,我们显然在单次操作时要去除已操作的边的影响,这样才可以保证单次至少可以筛出 \(\frac{n}{3}\) 条其他边。

通过 check 操作进行适当剪枝可以在 \(\mathcal O(50N)\) 的查询通过本题。

posted @ 2020-09-11 19:55  Soulist  阅读(122)  评论(0)    收藏  举报