QUERIES

Description:#

给定一个长度为 n 的序列 a1,a2,a3,...,an, 每个数大小不超过 1000;

有 m 次操作,每次操作改变一个数的值,或求一段区间 [l, r] 的所有子区间的异或和之和。

多组数据。 每个操作第一个数是 opt

  • 当 opt 为 1 时,读入 pos, val,表示修改第 pos 个数的值为 val。
  • 当 opt 为 2 时,读入 l, r, 表示询问 lijrikjak

Solution:#

Summary:#

线段树分治入门题。因为直接做看起来没什么思路,数的范围又在 1000 以内,考虑拆位算贡献。

Segmentreei 表示序列上数的第 i 位所构建的线段树。

对于线段树上每个点:

  • 定义 sum 为区间异或和。

  • l0、l1 表示区间内 从左到右连续的、异或和分别为 0、1 的子序列 个数。

    r0、r1 表示区间内 从右到左连续的、异或和分别为 0、1 的子序列 个数。

  • s0、s1 表示区间内 异或和分别为 0、1 的子序列 个数。

转移也十分显然:

sump=sumlssumrsl0,p=l0,ls+lsumls,rs,      l1,p=l1,ls+lsumls1,rsr0,p=r0,rs+rsumrs,ls,   r1,p=r1,rs+rsumrs1,lss0,p=s0,ls+s0,rs+l0,rsr0,ls+l1,rsr1,lss1,p=s1,ls+s1,rs+l1,rsr0,ls+l0,rsr1,ls

根据异或运算的规律 相同则 0, 不同为 1,可以很好理解上述转移式。

Detail:#

  • 空间比较紧,注意到 210=1024>1000,所以线段树理论开 9 棵即可。

  • 注意模数为 4001

  • 也许可以定义一个类,这样构造、修改、查询都方便。

Code:#

#include <bits/stdc++.h>
#define Rep(i, a, b) for (int i = (a), bb = (b); i <= bb; ++i)
const int N = 1e5 + 5, mod = 4001;
using namespace std;
int n, m, a[N], t, ans;
char BB[1 << 15], *S = BB, *T = BB;
#define getchar() (S == T && (T = (S = BB) + fread(BB, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
inline int read() { 
    int s = 0; char c = getchar(); for (; !isdigit(c); c = getchar()); 
    for (; isdigit(c); c = getchar()) s = (s << 3) + (s << 1) + c - 48; return s; 
}
template <class K> inline void write(K x) { 
    (x > 9 ? write(x / 10) : void()); 
    return putchar(x % 10 + 48), void(); 
}
inline int add(int a, int b) { return a + b >= mod ? a + b - mod : a + b; } 
inline void Add(int &a, int b) { return a = add(a, b), void(); }
inline int mul(int a, int b) { return 1LL * a * b % mod; } 
inline void Mul(int &a, int b) { return a = mul(a, b), void(); }
struct Se_P { 
    int sum, s[2], l[2], r[2]; 
    inline void clear(){sum = 0; Rep(i, 0, 1) s[i] = l[i] = r[i] = 0;}
} Void;
struct Segmentree { 
    Se_P t[N << 2], s; int tmp;
    #define sum(p) t[p].sum
    #define ls (p << 1)
    #define rs (ls | 1)
    #define mid ((x + y) >> 1)
    #define Ls ls, x, mid
    #define Rs rs, mid + 1, y
    inline Se_P Spread(Se_P l, Se_P r) { s.clear();
        s.s[0] = add(add(add(l.s[0], r.s[0]), mul(l.r[0], r.l[0])), mul(l.r[1], r.l[1]));
        s.s[1] = add(add(add(l.s[1], r.s[1]), mul(l.r[0], r.l[1])), mul(l.r[1], r.l[0]));
        
        if (l.sum == 0) s.l[0] = l.l[0] + r.l[0], s.l[1] = l.l[1] + r.l[1];
        else s.l[0] = l.l[0] + r.l[1], s.l[1] = l.l[1] + r.l[0];
                                        
        if (r.sum == 0) s.r[0] = r.r[0] + l.r[0], s.r[1] = r.r[1] + l.r[1];
        else s.r[0] = r.r[0] + l.r[1], s.r[1] = r.r[1] + l.r[0];
                                        
        s.sum = l.sum ^ r.sum;
        return s;
    }
    inline void Push(int p) { return t[p] = Spread(t[ls], t[rs]), void(); }
    inline void Build(int p, int x, int y, int op) { 
        t[p].clear();
        if (x == y) { 
            tmp = (a[x] & (1 << op)) ? 1 : 0; 
            return t[p].l[tmp] = t[p].r[tmp] = t[p].s[tmp] = 1, sum(p) = tmp, void(); 
        }
        return Build(Ls, op), Build(Rs, op), Push(p);
    }
    inline void Modify(int p, int x, int y, int pos, int v) {
        if (x == y) return t[p].clear(), t[p].l[v] = t[p].r[v] = t[p].s[v] = 1, sum(p) = v, void();
        (pos <= mid ? Modify(Ls, pos, v) : Modify(Rs, pos, v)), Push(p);
    }
    inline Se_P Ask(int p, int x, int y, int l, int r) {
        if (l > r || x > y || x > r || l > y) return Void;
        if (l <= x && y <= r) return t[p];
        return Spread(Ask(Ls, l, r), Ask(Rs, l, r));
    }
} Se[10];
int main(void) {
    n = read(), m = read(), Void.clear();
    Rep(i, 1, n) a[i] = read();
    Rep(i, 0, 9) Se[i].Build(1, 1, n, i);
    Rep(i, 1, m) {
        int opt = read(), x = read(), y = read();
        if (opt == 1) { 
            Rep(i, 0, 9) Se[i].Modify(1, 1, n, x, (y & (1 << i)) ? 1 : 0); 
        }
        if (opt == 2) { 
            t = 1, ans = 0;
            Rep(i, 0, 9) Add(ans, mul(Se[i].Ask(1, 1, n, x, y).s[1], t)), Mul(t, 2);
            write(ans), putchar(10);
        }
    }
    return 0;
}
posted @   云烟万象但过眼  阅读(300)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示
主题色彩