Comet OJ - Contest #8 D.菜菜种菜【树状数组】

菜菜种菜

已经提交 已经通过 时间限制: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​] 中的所有土地。

  • 1\le n,m,q \le 10^61≤n,m,q≤106
  • 1\le a_i\le 3001≤ai​≤300
  • 1\le u_i,v_i\le n,u_i\neq v_i1≤ui​,vi​≤n,ui​​=vi​
  • 1\le l_i\le r_i\le n1≤li​≤ri​≤n。

输出描述

 

为了避免输出量过大,设 ans_iansi​ 表示第 ii 个询问的答案。你只需要输出 11 行 11 个整数 {\rm xor}_{i=1}^qi\times ans_ixori=1q​i×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;
}

 

你可能感兴趣的:(Comet OJ - Contest #8 D.菜菜种菜【树状数组】)