The 2019 ICPC China Nanchang National Invitational and International Silk-Road Programming Contest - F.Sequence(打表+线段树)

题意:给你一个长度为$n$的数组,定义函数$f(l,r)=a_{l} \oplus a_{l+1} \oplus...\oplus a_{r}$,$F(l,r)=f(l,l)\oplus f(l,l+1)\oplus ...\oplus f(l,r)\oplus f(l+1,l+1)\oplus ...f(l+1,r)\oplus ...\oplus f(r,r)$,有两种操作,第一种将数组中某个元素$a[x]$变为$y$,第二种计算$F(l,r)$的值。

思路:打表后发现只有当$l$和$r$同时为奇数或者偶数时$F(l,r)$才不为$0$,其他情况下$F(l,r)$都为$0$,并且$F(l,r)=a[l]\oplus a[l+2]\oplus ...\oplus a[r-2]\oplus a[r]$,由于涉及到修改和查询两种操作,所以用线段树来维护,每个结点维护两个值:$w$表示区间内奇数项异或的结果,$ww$表示区间内偶数项异或的结果。

初始建树时

  • 当前项为奇数项,则输入$tree[k].w$的值,同时令$tree[k].ww=0$
  • 当前项为偶数项,则输入$tree[k].ww$的值,同时令$tree[k].w=0$

修改操作时

  • 需要修改的项为奇数项,则对$tree[k].w$进行修改
  • 需要修改的项为偶数项,则对$tree[k].ww$进行修改

查询操作时

  • 如果$l$为奇数,则用$ans=ans\oplus tree[k].w$来更新答案
  • 如果$l$为偶数,则用$ans=ans\oplus tree[k].ww$来更新答案
#include <iostream>
#include <cstdio>

using namespace std;

const int N = 100010;

struct node {
    int l, r, w, ww;
};

int a, b, x, y, ans;
node tree[4 * N];

void build(int k, int lef, int rig)
{
    tree[k].l = lef, tree[k].r = rig;
    if (tree[k].l == tree[k].r) {
        if (0 == tree[k].l % 2) {
            tree[k].w = 0, scanf("%d", &tree[k].ww);
        }
        else {
            tree[k].ww = 0, scanf("%d", &tree[k].w);
        }
        return;
    }
    int mid = (lef + rig) / 2;
    build(k * 2, lef, mid); build(k * 2 + 1, mid + 1, rig);
    tree[k].w = tree[k * 2].w ^ tree[k * 2 + 1].w;
    tree[k].ww = tree[k * 2].ww ^ tree[k * 2 + 1].ww;
}

void change_point(int k)
{
    if (tree[k].l == tree[k].r) {
        if (tree[k].l % 2 == 0) tree[k].ww = y;
        else tree[k].w = y;
        return;
    }
    int mid = (tree[k].l + tree[k].r) / 2;
    if (x <= mid) change_point(2 * k);
    else change_point(2 * k + 1);
    tree[k].w = tree[2 * k].w ^ tree[2 * k + 1].w;
    tree[k].ww = tree[2 * k].ww ^ tree[2 * k + 1].ww;
}

void ask_interval(int k)
{
    if (tree[k].l >= a && tree[k].r <= b) {
        if (0 == a % 2) ans ^= tree[k].ww;
        else ans ^= tree[k].w;
        return;
    }
    int mid = (tree[k].l + tree[k].r) / 2;
    if (a <= mid) ask_interval(2 * k);
    if (b > mid) ask_interval(2 * k + 1);
}

int main()
{
    int T, t, n, q, icas = 0;
    scanf("%d", &T);
    while (T--) {
        printf("Case #%d:\n", ++icas);
        scanf("%d%d", &n, &q), build(1, 1, n);
        while (q--) {
            scanf("%d", &t);
            if (0 == t) {
                scanf("%d%d", &x, &y);
                change_point(1);
            }
            else {
                ans = 0, scanf("%d%d", &a, &b);
                if (a % 2 == b % 2) ask_interval(1);
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zzzzzzy/p/11706173.html
今日推荐