题意:给你一个数组a,长度为。有两种操作。一种是改变数组的某个元素的值,一种是满足某种条件的数组b有多少种。条件是:b[i] <= a[i],并且b[1]^b[2]...^b[n] = k的数组有多少种。数组a的元素都小于1000.

思路:因为数很小,我们把数变成二进制数,然后拆分二进制数。比如1101可以拆成10xx,x可为0可为1,有点像数位dp的试填法。我们对每个a[i]存若干个前缀,记录前缀的长度,以及是这个前缀的二进制数有多少个。然后我们合并相邻的区间,直接暴力二重循环,然后合并。其实这个过程更像dp的过程,感觉只是用了线段树的划分成区间,然后合并的思想。

思路参考这两篇博客:https://blog.csdn.net/jtjy568805874/article/details/56488626, https://blog.csdn.net/qian99/article/details/38171951

代码:

#include <bits/stdc++.h>
#define pii pair<int, int>
#define lowbit(x) (x & (-x))
#define mk make_pair
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
#define LL long long
using namespace std;
const LL mod = 1000000007;
const int maxn = 20010; int Log[2010], a[maxn];
struct node {
pii x;
LL tot;
bool operator < (const node& rhs) const {
return x < rhs.x;
}
}; vector<node> tr[maxn * 4], tmp; int get(int x, int y) {
tr[x].clear();
tr[x].push_back((node){mk(y, 10), 1});
for (int i = y; i; i -= lowbit(i)) {
tr[x].push_back((node){mk(i - lowbit(i), 10 - Log[lowbit(i)]), lowbit(i)});
}
} void pushup(int x, int l, int r) {
tmp.clear();
tr[x].clear();
for (int i = 0; i < tr[l].size(); i++) {
for (int j = 0; j < tr[r].size(); j++) {
node t1 = tr[l][i], t2 = tr[r][j];
int now = t1.x.first ^ t2.x.first, len = min(t1.x.second, t2.x.second);
now = ((now >> (10 - len)) << (10 - len));
tmp.push_back((node){mk(now, len), (t1.tot * t2.tot) % mod});
}
}
sort(tmp.begin(), tmp.end());
for (int i = 0, j; i < tmp.size(); i = j) {
node tmp1 = (node){tmp[i].x, 0};
for (j = i; j < tmp.size() && tmp[i].x == tmp[j].x; j++) {
tmp1.tot = (tmp1.tot + tmp[j].tot) % mod;
}
tr[x].push_back(tmp1);
}
} void build(int x, int l, int r) {
if(l == r) {
get(x, a[l]);
return;
}
int mid = (l + r) >> 1;
build(ls(x), l ,mid);
build(rs(x), mid + 1, r);
pushup(x, ls(x), rs(x));
} LL inv(int x) {
return x == 1 ? 1 : 1ll * inv(mod % x)*(mod - mod / x) % mod;
} void update(int x, int l, int r, int pos, int val) {
if(l == r) {
get(x, val);
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(ls(x), l, mid, pos, val);
else update(rs(x), mid + 1, r, pos, val);
pushup(x, ls(x), rs(x));
} LL query(int x) {
LL ans = 0;
for (int i = 0; i < tr[1].size(); i++) {
node t = tr[1][i];
if((t.x.first ^ x) >> (10 - t.x.second)) continue;
ans = (ans + (t.tot * inv(1 << (10 - t.x.second))) % mod) % mod;
}
return ans;
}
int main() {
int n, m;
int x, y;
char s[10];
for (int i = 1; i <= 10; i++)
Log[1 << i] = i;
int T;
cin >> T;
while(T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
build(1, 1, n);
while(m--) {
scanf("%s",s + 1);
if(s[1] == 'Q') {
scanf("%d", &x);
printf("%lld\n", query(x));
} else {
scanf("%d%d", &x, &y);
update(1, 1, n, x + 1, y);
}
}
}
}

  

线段树教做人系列(2)HDU 4867 XOR的更多相关文章

  1. 线段树教做人系列(3) HDU 4913

    题意及思路看这篇博客就行了,讲得很详细. 下面是我自己的理解: 如果只有2,没有3的话,做法就很简单了,只需要对数组排个序,然后从小到大枚举最大的那个数.那么它对答案的贡献为(假设这个数排序后的位置是 ...

  2. Codeforces 719E (线段树教做人系列) 线段树维护矩阵

    题面简洁明了,一看就懂 做了这个题之后,才知道怎么用线段树维护递推式.递推式的递推过程可以看作两个矩阵相乘,假设矩阵A是初始值矩阵,矩阵B是变换矩阵,求第n项相当于把矩阵B乘了n - 1次. 那么我们 ...

  3. 线段树教做人系列(1)HDU4967 Handling the Past

    题意:给你n组操作,分别为压栈,出栈,询问栈顶元素.每一组操作有一个时间戳,每次询问栈顶的元素的操作询问的是在他之前出现的操作,而且时间戳小于它的情况.题目中不会出现栈为空而且出栈的情况. 例如: p ...

  4. Codeforces 1136E Nastya Hasn't Written a Legend (线段树教做人系列)

    题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后, ...

  5. 线段树(单点更新,区间查询) HDU 1754 I Hate It

    题目链接 线段树的模板 #include<iostream> #include<cstdio> #include<cmath> #include<algori ...

  6. 线段树(区间合并)HDU - 1540

    题意:输入n,m,给定n个相互连通的村庄,有m个操作,D x,表示破坏x村庄使其与相邻的两个村庄不相通,R 表示修复上一个被破坏的村庄,与相邻的两个村庄联通.Q x表示与x相连的村庄有多少个. 思路: ...

  7. (线段树 区间查询)The Water Problem -- hdu -- 5443 (2015 ACM/ICPC Asia Regional Changchun Online)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=5443 The Water Problem Time Limit: 1500/1000 MS (Java/ ...

  8. (线段树)Just a Hook -- hdu -- 1689

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=1698 思路: 我的想法很简单,像上一题一样从后面向前面来算,前面已经覆盖的,后面自然不能再来计算了,具体 ...

  9. 线段树(区间修改、区间查询) HDU 1754 I Hate It

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

随机推荐

  1. 如何理解python中的if __name__=='main'的作用

    一. 一个浅显易懂的比喻 我们在学习python编程时,不可避免的会遇到if __name__=='main'这样的语句,它到底有什么作用呢? <如何简单地理解Python中的if __name ...

  2. 51nod 1437

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1437 1437 迈克步 题目来源: CodeForces 基准时间限制: ...

  3. oracle for loop 简单

    declare i NUMBER; begin loop INSERT INTO emp VALUES(i,i); end LOOP; END;

  4. EXCEL对比重复数据

    一.       EXCEL 突出重复项 1.      选择对应的数据 EXCEL 里选择好数据 2.      选择条件格式 这样就完成了数据重复的突出,可以按条件筛选.选择自己想要的数据

  5. ServlertContext

    1.ServletContext代表着整个JavaWeb应用,每个项目只有唯一的ServletContext的实例. 2.生命周期 服务器启动时创建 服务器关闭时销毁 3.获取ServletConte ...

  6. webpack 配置简单说几句 ?

    前言 这几天在准备一个单页面应用, 准备试试webpack神器,在准备webpack下的知识点,顺便记录下一些使用的心得. webpack 的配置说明 在近来的前端开发中,业务逻辑复杂化,层次多样化, ...

  7. ubuntu 迁移部分 / 目录下的存储空间到 /home目录

    状况:当时给系统分区的时候,home和根目录都是25GB左右,突然发现home 目录不够用了,于是决定进行将根目录的部分空间挪移到home下去 主要方法:使用Gparted的LIve USB的方法. ...

  8. BZOJ2002:[HNOI2010]弹飞绵羊

    浅谈分块:https://www.cnblogs.com/AKMer/p/10369816.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?i ...

  9. java中final用法

    1.修饰基础数据成员 这是final的主要用途,其含义相当于C/C++的const,即该成员被修饰成常量,不可修改. 2.修饰类或者对象的引用的final 在java中我们无法让对象被修饰为final ...

  10. (转)C# 特性(Attribute)详细介绍

    本文转载自:http://www.cnblogs.com/luckdv/articles/1682488.html 1.什么是Atrribute 首先,我们肯定Attribute是一个类,下面是msd ...