传送门
官方题解 (讲的很好)
解法:我们将所有土地排成一行,可以很好的转化为区间问题,每次询问一个区间 [L,R] 中符合条件土地的菜值和。想要一个土地符合条件,它能够到达的土地必须在询问区间之外或者不存在。意思就是它左边最近能够到达的土地 x ( 满足条件 x<L ,不存在可以到达的土地 x=0 ),同理它右边最近能够到达的土地 y (满足条件 y>R ,不存在可以到达的土地 y=n+1 )。
上面的条件可以转化为一个三维数点的问题,满足这些条件土地的菜值和。
我们记作 为满足 的土地菜值之和。
答案我们看为
利用容斥原理(类似二维前缀和求矩形面积)
式子第一项 是一个区间和(前缀和搞定)
式子第二项 只需要满足 。
式子第三项 只需要满足 。
式子第四项 只需要满足 。
可以发现将三维数点问题转化为三个二维数点问题,将所有询问离线,点和询问按第一维排序,第二维作为 下标,顺次扫描,遇到一个点将它第二维对应的位置加上它的权值,遇到一个 询问就查询对应第二维的对应的区间和,只需一个支持单点加,区间求和的数据结构,树状数组即可胜任。
代码:
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
int read() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') { x = x * 10 + (ch - '0'), ch = getchar(); }
return x * w;
}
int n, m, q;
int x[maxn], y[maxn], a[maxn], pre[maxn];
int ans[maxn];
ll low[maxn];
struct node {
int l, r, id, add;
} Q[maxn], temp[maxn << 1];
bool cmp(node a, node b) { return a.l == b.l ? a.id < b.id : a.l > b.l; }
void add(int i, int add) {
if (i == 0) return;
while (i <= n) { low[i] += add, i += lowbit(i); }
}
ll sum(int i) {
ll all = 0;
while (i > 0) { all += low[i], i -= lowbit(i); }
return all;
}
/// L<=x[i],i<=R
void solve_1() {
for (int i = 0; i <= n + 1; i++)low[i] = 0;
for (int i = 1; i <= q; i++)temp[i] = Q[i];
for (int i = 1; i <= n; i++)temp[i + q] = node{x[i], i, 0, a[i]};
sort(temp + 1, temp + 1 + n + q, cmp);
for (int i = 1; i <= n + q; i++) {
if (temp[i].id)ans[temp[i].id] -= sum(temp[i].r);
else add(temp[i].r, temp[i].add);
}
}
/// L<=i y[i]<=R
void solve_2() {
for (int i = 0; i <= n + 1; i++)low[i] = 0;
for (int i = 1; i <= q; i++)temp[i] = Q[i];
for (int i = 1; i <= n; i++)temp[i + q] = node{i, y[i], 0, a[i]};
sort(temp + 1, temp + 1 + n + q, cmp);
for (int i = 1; i <= n + q; i++) {
if (temp[i].id)ans[temp[i].id] -= sum(temp[i].r);
else add(temp[i].r, temp[i].add);
}
}
///L<=x[i] y[i]<=R
void solve_3() {
for (int i = 0; i <= n + 1; i++)low[i] = 0;
for (int i = 1; i <= q; i++)temp[i] = Q[i];
for (int i = 1; i <= n; i++)temp[i + q] = node{x[i], y[i], 0, a[i]};
sort(temp + 1, temp + 1 + n + q, cmp);
for (int i = 1; i <= n + q; i++) {
if (temp[i].id)ans[temp[i].id] += sum(temp[i].r);
else add(temp[i].r, temp[i].add);
}
}
int main() {
n = read(), m = read(), q = read();
for (int i = 1; i <= n; i++) {
a[i] = read();
pre[i] = pre[i - 1] + a[i];
x[i] = 0, y[i] = n + 1;
}
int u, v;
for (int i = 1; i <= m; i++) {
u = read(), v = read();
if (u > v)x[u] = max(x[u], v);
else y[u] = min(y[u], v);
}
for (int i = 1; i <= q; i++) {
Q[i].l = read();
Q[i].r = read();
ans[i] = pre[Q[i].r] - pre[Q[i].l - 1];
Q[i].id = i;
}
solve_1(), solve_2(), solve_3();
ll all = 0;
for (int i = 1; i <= q; i++) all = all ^ (1LL * ans[i] * i);
printf("%lld\n", all);
return 0;
}