【AtCoder】F - Adding Chords (破环成链 + 异或哈希 + 树状数组)
·
题目:
思路:
异或性质 + 经典trick
遇到环上问题 or 树上问题,我们都可以往链上想
本题就是破环成链,我们将一个线段放在链上,可以发现其连接了两个点,那么如果此后如果加入了一个线段,那么就有以下三种情况(红色线段是最先画的,其余线段是下一个加入的线段的可能情况)

①.新加的线段与原来的线段端点不相交
此时显然是没有相交的
②.新加的线段与原来的线段端点 相交一个
此时就是二者相交了
③.新加的线段与原来的线段端点不相交
此时显然是没有相交的
所以可以想到一个结论:如果新加入的区间之间 包含了 别的区间一个端点,那么此时就是不能加入的
那么如何判断呢?
想想异或的性质,对于偶数个相同的数异或,那么结果就是 0,否则就是这个数本身
所以我们可以利用区间异或和,对于每个线段,如果其可以放,那么就相当于给 l,r 赋值了一个 id 值,那么判断是否相交就是判断 sum[r] ^ sum[l-1] 是否为 0 即可
但是会有特殊情况,如果我们赋值的是操作的 id,那么对于 1 ^ 2 ^ 3 = 0,但是此时是不合法的,因为都有三个线段的各一个端点了,显然相交
为了防止这种情况,我们可以使用异或哈希,即每次赋值的不是操作 id,而是一个随机数,这样就能解决这个问题了
那么对于单点修改 + 区间查询,我们直接上树状数组即可
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());
int n;
int bittree[1000006];
int lowbit(int x) { return x & -x; }
void update(int x, int k)
{
for (; x <= n; x += lowbit(x))
bittree[x] ^= k;
}
int sum(int x)
{
int res = 0;
for (; x; x -= lowbit(x))
res ^= bittree[x];
return res;
}
int query(int a, int b)
{
return sum(b) ^ sum(a - 1);
}
void solve()
{
int q;
cin >> n >> q;
while (q--)
{
int a, b;
cin >> a >> b;
if (query(a, b) == 0)
{
yes;
int rd = rnd();
update(a, rd);
update(b, rd);
}
else
{
no;
}
}
}
signed main()
{
cin.tie(0)->sync_with_stdio(0);
int t = 1;
while (t--)
{
solve();
}
return 0;
}
更多推荐



所有评论(0)