菜菜种菜
已经提交 已经通过 时间限制:2000ms 内存限制:128MB
64.15%
提交人数:106
通过人数:68
题目描述
菜菜太菜,但他不想种菜。
有 nn 块土地,每块土地有一个菜值。它们之间有 mm 条小路,每条连接两块土地,小路只能单向通行,不存在一条小路两端连接同一块土地,但可能存在两条小路两端连接的土地分别相同。如果存在一条从土地 uu 到土地 vv 的小路,则称 uu 能直接到达 vv。
菜菜可以购买一些土地,他必须在其中选择一块建造自己的家,所购买的剩下的土地都被作为菜地。因为菜菜不想种菜,所以他希望从他家能直接到达的土地中,一块菜地也没有(如果菜菜家不能直接到达任何一块土地,这也能满足他的愿望)。
菜菜提出了 qq 个问题,每个问题给出 L,RL,R ,询问如果他购买了第 LL 到第 RR 块之间的所有土地,那么所有满足他愿望的建造家的选址的菜值之和是多少?
注意,本题空间限制为128MB
P.S. 本题标算有使用读入优化,相关资讯可参考oi-wiki --- 读入、输出优化
输入描述
第 11 行 33 个由空格隔开的整数 n,m,qn,m,q ,分别表示土地的块数、小路的条数和问题的个数。
第 22 行 nn 个由空格隔开的整数,第 ii 个数 a_iai 表示第 ii 块土地的菜值。
接下来 mm 行,每行 22 个由空格隔开整数 u_i,v_iui,vi,表示第 ii 条小路从第 u_iui 块土地通向第 v_ivi 块土地。
接下来 qq 行,每行 22 个由空格隔开整数 l_i,r_ili,ri,表示菜菜第 ii 个问题中购买了 [l_i,r_i][li,ri] 中的所有土地。
输出描述
为了避免输出量过大,设 ans_iansi 表示第 ii 个询问的答案。你只需要输出 11 行 11 个整数 {\rm xor}_{i=1}^qi\times ans_ixori=1qi×ansi,即所有询问的编号与答案的乘积依次按位异或 (c++中的64位整数^
)的结果。
样例输入 1
4 2 2 3 5 10 6 1 4 2 3 2 3 1 3
样例输出 1
16
样例输入 2
5 6 3 114 29 219 231 165 5 4 1 2 1 3 5 3 3 2 3 4 2 2 1 2 4 5
样例输出 2
658
提示
对于样例1:第 11 次询问,33 号土地不能直接到达任何土地,是满足要求的,而 22 号土地能到达 33 号土地,33 在 [2,3][2,3] 之内是菜地,不能满足要求,所以这次询问的答案为 1010;第 22 次询问,11 号土地只能到达 44 号土地,不在 [1,3][1,3] 内,是满足要求的,33 号土地仍然满足要求,所以这次询问的答案为 1313。输出 (1\times10){\rm xor} (2\times13)=16(1×10)xor(2×13)=16 。
分析:比较容易想到,每个点都能对一些询问的区间产生贡献,这些区间的范围是由这个点的边决定的。
首先,这些区间要包含这个点,但又不能包含与这个点相连的边,令区间表示为[L,R],有x<=L<=i,i<=R<=y,其中i表示这个点,x表示从i出去的点中所有小于i的最大的,y表示从i出去的点中所有大于i的最小的,具体画个图就清楚了。
现在我们得到了每个点能产生贡献的范围,问题在于如何统计贡献,也是一个比较套路的问题了,一般都使用bit来维护。
对于左端点很容易确定,将询问按L排序后,每次把不包含L的删掉,把包含L的加进去就可以了。
对于右端点,每个点有一个取值范围是[i,y],因为我们只需要查询总和,所以在i的位置add上a[i],在y+1位置上add上-a[i],这样对于大于这个询问,就可以将贡献抵消掉了。
#include "bits/stdc++.h"
namespace fastIO {
#define BUF_SIZE 100000
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
inline void read(int &x) {
char ch;
while (blank(ch = nc()));
if (IOerror) return;
// bool flag = 0;
// if (ch == '-') {
// ch = nc();
// flag = 1;
// }
for (x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
// if (flag)x = -x;
}
inline void Out(int a) {
if (a < 0) {
putchar('-');
a = -a;
}
if (a >= 10) {
Out(a / 10);
}
putchar(a % 10 + '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
using namespace std;
struct BIT {
int n;
vector v;
BIT(int n) : n(n) {
v.resize(n + 1);
}
void update(int x, int d) {
while (x <= n) {
v[x] += d;
x += (x & -x);
}
}
int que(int x) {
int res = 0;
while (x > 0) {
res += v[x];
x -= (x & -x);
}
return res;
}
} bit(1000004);
int a[1000004];
int ans[1000004];
int r[1000004];
struct node {
int l, r, id;
bool friend operator<(node a, node b) {
if (a.l == b.l)return a.r < b.r;
else return a.l < b.l;
}
} b[1000004], c[1000004];
priority_queue, greater > pq;
int main() {
int n, m, q;
read(n);
read(m);
read(q);
for (int i = 1; i <= n; ++i) {
read(a[i]);
c[i].l = 1, c[i].r = r[i] = n;
c[i].id = i;
}
for (int i = 1; i <= m; ++i) {
int u, v;
read(u);
read(v);
if (v < u)c[u].l = max(c[u].l, v + 1);
else {
r[u] = c[u].r = min(c[u].r, v - 1);
}
}
for (int i = 1; i <= q; ++i) {
read(b[i].l);
read(b[i].r);
b[i].id = i;
}
sort(b + 1, b + 1 + q);
sort(c + 1, c + 1 + n);
int cnt = 1;
for (int i = 1; i <= q; ++i) {
while (cnt <= n && b[i].l >= c[cnt].l) {
bit.update(c[cnt].id, a[c[cnt].id]);
bit.update(c[cnt].r + 1, -a[c[cnt].id]);
pq.push(c[cnt].id);
cnt++;
}
while (pq.size() && pq.top() < b[i].l) {
int id = pq.top();
pq.pop();
bit.update(id, -a[id]);
bit.update(r[id] + 1, a[id]);
}
ans[b[i].id] = bit.que(b[i].r);
}
long long res = 0;
for (int i = 1; i <= q; ++i) {
res ^= 1LL * i * ans[i];
}
cout << res << endl;
}