思路
我们可以考虑使用线段树来维护区间的面积(对于一对不认识的人,可以在二维空间中用一个边为\(1\)的块来表示。这时我们的问题便转换成为在坐标系中某一范围内的面积(面积就是区间内认识的人数)。我们再进行研究,就会发现每一次操作一次区间,我们操作的图形在二维坐标系上就会表示成两个对点落在\(y=x\)这条直线上。我们首先给直线\(y=x\)上的点描黑(自己总会认识自己),然后写一个线段树。我们在合并两个区间的时候需要注意,如果合并时涉及到两个矩形重叠,那么我们需要取最高的值来表示矩形的上边缘。在区间内,上边缘的高度一定是单调递增的,所以我们可以二分出一个高度小于覆盖高度的偏移量,这样可以加速合并。具体请看代码:
代码
// T44990.cpp
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ls (p << 1)
#define rs ((p << 1) | 1)
#define mid ((l + r) >> 1)
#define ll long long
using namespace std;
const ll maxn = 1000000 + 2000;
ll n, q, xl, xr, sum[maxn << 2], upper[maxn << 2], tag[maxn << 2];
// segment tree;
void pushdown(ll p, ll l, ll r)
{
if (tag[p] != 0)
{
tag[ls] = tag[rs] = tag[p];
upper[ls] = max(upper[ls], tag[p]);
upper[rs] = max(upper[rs], tag[p]);
sum[ls] = 1LL * tag[p] * (mid - l + 1);
sum[rs] = 1LL * tag[p] * (r - mid);
tag[p] = 0;
}
}
void pushup(ll p)
{
sum[p] = sum[ls] + sum[rs];
upper[p] = max(upper[ls], upper[rs]);
}
void build(ll l, ll r, ll p)
{
if (l == r)
{
sum[p] = upper[p] = l;
return;
}
build(l, mid, ls);
build(mid + 1, r, rs);
pushup(p);
}
void update(ll ql, ll qr, ll l, ll r, ll p, ll c)
{
if (ql > r || qr < l)
return;
if (ql <= l && r <= qr)
{
sum[p] = 1LL * (r - l + 1) * c, tag[p] = upper[p] = c;
return;
}
pushdown(p, l, r);
update(ql, qr, l, mid, ls, c);
update(ql, qr, mid + 1, r, rs, c);
pushup(p);
}
ll query(ll ql, ll qr, ll l, ll r, ll p)
{
if (ql > r || qr < l)
return 0;
if (ql <= l && r <= qr)
return sum[p];
pushdown(p, l, r);
return query(ql, qr, l, mid, ls) + query(ql, qr, mid + 1, r, rs);
}
ll find(ll l, ll r, ll p, ll strd)
{
if (l == r)
return l;
pushdown(p, l, r);
if (upper[ls] >= strd)
return find(l, mid, ls, strd);
else
return find(mid + 1, r, rs, strd);
}
int main()
{
scanf("%lld%lld", &n, &q);
build(0, n, 1);
ll lastans = 0;
for (ll i = 0; i < q; i++)
{
scanf("%lld%lld", &xl, &xr);
xl ^= lastans, xr ^= lastans;
ll pos = find(0, n, 1, xr) - 1;
if (pos < xl)
lastans = 0;
else
{
ll res = query(xl, pos, 0, n, 1);
lastans = 1LL * (pos - xl + 1) * xr - res;
update(xl, pos, 0, n, 1, xr);
}
printf("%lld\n", lastans);
}
return 0;
}